数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
思路有下面几种:
1. 使用一个map结构,保存所有数字出现的次数。
2. 排序的思想,如果是一个已排序的数组, 其中有长度超过一半的元素,则一定是数组中间的元素,先排序,再判断中间的元素个数是否超过数组长度的一半。
3. 打擂台的思想, 数组中同时去掉两个不同的数,最后剩下的就是结果
代码如下:
class Solution {
public:
//方法一:如果是已排序的数组, 如果有一个数字个数大于长度的一半,则一定是数组中间的数字
// 所以先将数组排序,然后取中间的数字,判断出现的个数是否大于一半
int get_more_than_halfnum_sort(vector<int>& numbers){
sort(numbers.begin(), numbers.end());
int cnt = 0;
int mid = numbers.size()/2;
for(int i = 0; i < numbers.size(); ++i){
if(numbers[i] == numbers[mid]){
cnt++;
}
}
return cnt > mid ? numbers[mid] : 0;
}
//方法二:打擂台的思想,设想数组的所有元素在一个擂台上,
// 如果有一个数字个数大与一半,则其可以1:1的将值不同的元素PK出去,剩下一个以上的胜利者值相同
// 反过来,数组元素一个一个的上擂台,如果第一个和第二和值不同,则两个同时下台,
// 如果两个值相同,则守擂人数加1
// 最后守擂的就可能是个数超过一半的(少数派可能会内耗...)
int get_more_than_halfnum_pk(vector<int>& numbers){
if(0 == numbers.size()){
return 0;
}
int cnt = 1;
int num = numbers[0];
for(int i = 1; i < numbers.size(); ++i){
if(0 == cnt){ //如果擂台是空的,则当前元素上台
num = numbers[i];
cnt = 1;
}
else{ //擂台不空 则值相同则+1 不同则-1(两个同时下台)
cnt = (num == numbers[i]) ? cnt+1 : cnt-1;
}
}
if(0 == cnt){ //最后台上一个都没有了,则肯定没有超过一半的元素
return 0;
}
else{
cnt = 0;
for(int i = 0; i < numbers.size(); ++i){
if(numbers[i] == num){
cnt++;
}
}
return cnt > numbers.size()/2 ? num : 0;
}
}
int MoreThanHalfNum_Solution(vector<int> numbers) {
//return get_more_than_halfnum_sort(numbers);
return get_more_than_halfnum_pk(numbers);
}
};