题目描述:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
输入:
每个测试案例包括2行:
第一行输入一个整数n(1<=n<=100000),表示数组中元素的个数。
第二行输入n个整数,表示数组中的每个元素,这n个整数的范围是[1,1000000000]。
输出:
对应每个测试案例,输出出现的次数超过数组长度的一半的数,如果没有输出-1。
样例输入:
9 1 2 3 2 2 2 5 4 2
样例输出:
2
思路:根据题意,要找到数字个数超过总个数的一般的数值。那么我们可以想到如果这些数据是排序的,并且存在这样一个数,那么是不是这个数字的中值一定就是这个数(好好理解下)
解法一:根据上面思路,并且假设输入数据的值可以改变。那么利用快排,将数组排序(剑指offer上讲的解法一,我的理解就是单纯快排,根据这种方法。但是自己手写的partition函数,最后一组T了,据说算导上具体写了)。时间复杂度为O(n*logn)。再通过一次遍历,判断是否存在满足条件的数字,时间复杂度为O(n)。所以这种方法的总的时间复杂度为O(n*logn + n) ==O(n);
解法二:可以参照上面的思路(但不是找中值).根据题意,找一个数值个数超过总数一半的数。那么就意味着其他数据的个数总和就小于这个数的个数。由此,我们就只需要采用二进制数1,0.用来表示,是或不是该数。因此我们利用两个变量pos和sum。分别表示当前pos数据,和当前pos数据的个数。从头到尾遍历一遍。当遍历的数值等于当前数据pos时,那么当前数据的个数sum+1;否则sum-1;如果这个数据的个数为0.就把遍历位置的数据存入当前pos数据,并且使sum=1;按照这种思路遍历到最后一个数据,就能得出满足题意得值。时间复杂度为O(n)。最后在遍历一个,检验数据。总的时间复杂度为O(2*n)==O(n );
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<queue>
#include<algorithm>
#include<functional>
#include<stack>
using namespace std;
const int MAX = 100005;
int num[MAX ], temp[ MAX ];
int CheckInvalidArray(int *num, int length){
if (num == NULL ?? length <= 0)
return true;
return false;
}
int CheckMoreThanHalf(int *num, int length, int pos){
int sum = 0;
for (int i = 0; i < length; ++i){
if (num[i] == pos)
sum++;
}
if (2 * sum <= length)
return false;
return true;
}
int main(){
int n;
while (cin >> n){
for (int i = 0; i < n; ++i)
cin >> num[i];
if (CheckInvalidArray(num, n))
return 0;
int sum = 0;
int pos = num[0];
for (int i = 1; i < n; ++i){
if (sum == 0){
sum = 1;
pos = num[i];
}
if (pos == num[i]){
sum++;
}
else
sum--;
}
if (!CheckMoreThanHalf(num, n, pos))
pos = 0;
if (pos)
cout << pos << endl;
else
puts("-1");
}
return 0;
}