在数组中找到出现次数大于一半的数

在数组中找到出现次数大于一半的数

题目描述

给定一个整型数组arr,请打印其中出现次数大于一半的数,如果没有这样的数,请输出-1。

输入描述:

输入包含两行,第一行包含一个整数 n ( 1 ≤ n ≤ 1 0 5 ) n(1 \leq n \leq 10^5) n(1n105)代表数组长度,第二行包含n个数,代表数组 a r r ( 1 ≤ a r r i ≤ 1 0 9 ) arr(1 \leq arr_i \leq 10^9) arr(1arri109)

输出描述:

输出一个整数,代表出现次数大于一半的数,如果没有这样的数,请输出‘-1“。

示例1
输入
5
11 7 5 7 7
输出
7
示例2
输入
4
2 2 3 3
输出
-1
备注:

时间复杂度 O ( n ) O(n) O(n),额外空间复杂度 O ( 1 ) O(1) O(1)


题解:

常规解法可以尝试使用哈希表记录每个元素出现的次数,但是额外空间复杂度不满足题目要求。考虑一个比较新颖的做法:每次我们删除两个不一样的元素,如果序列中存在出现次数超过一半的元素,那么该元素最后一定会被保留下来。这样的话,我们可以只用两个变量就搞定了(具体见代码)。

注意:最后保存的不一定是出现次数超过一半的元素,还需要在遍历一边数组,确认一下。

代码:
#include <cstdio>

using namespace std;

const int N = 100010;

int n;
int a[N];

int main(void) {
    
    
    scanf("%d", &n);
    int cand = 0;
    int times = 0;
    for ( int i = 0; i < n; ++i ) {
    
    
        scanf("%d", a + i);
        if ( !times ) {
    
    
            cand = a[i];
            times = 1;
        } else if ( a[i] == cand ) ++times;
        else --times;
    }
    if ( !cand ) return 0 * puts("-1");
    times = 0;
    int mid = n >> 1;
    for ( int i = 0; i < n && times <= mid; ++i ) times += ( a[i] == cand );
    if ( times > mid ) printf("%d\n", cand);
    else puts("-1");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/MIC10086/article/details/109277514