题目描述:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
1、方法一
/*
* 采用阵地攻守的思想:
* 第一个数字作为第一个士兵,守阵地;count = 1;
* 遇到count为0的情况,又以新的i值作为守阵地的士兵,
* 遇到相同元素,count++;
* 遇到不相同元素,即为敌人,同归于尽,count--;
* 到最后还留在阵地上的士兵,有可能是主元素。记录这个可能的主元素的个数是否大于数组一半即可确定返回值。
*/
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> array) {
int length=array.size();
if(length<=0)
{
return 0;
}
if(length==1)
{
return array[0];
}
//第一个数字作为第一个士兵,守阵地;count = 1;
int count = 1;
int cur = array[0];
for(int i=1;i<length;i++)
{
if (count == 0) //遇到count为0的情况,又以新的i值作为守阵地的士兵,
{
cur = array[i];
count = 1;
}
else if (cur == array[i])//遇到相同元素,count++;
{
count++;
}
else//遇到不相同元素,即为敌人,同归于尽,count--;
{
count--;
}
}
//统计该数字的个数
int times=0;
for(int i=0;i<length;i++)
{
if (cur == array[i])
{
times++;
}
}
return 2*times >= length ? cur : 0;
}
}
2、方法二
/*
* 采用用户“分形叶”思路(注意到目标数 超过数组长度的一半,对数组同时去掉两个不同的数字,
* 到最后剩下的一个数就是该数字。如果剩下两个,那么这两个也是一样的,就是结果),在其基础上把最
* 后剩下的一个数字或者两个回到原来数组中,将数组遍历一遍统计一下数字出现次数进行最终判断。
*/
public class Solution {
int MoreThanHalfNum_Solution(vector<int> array) {
int length=array.length;
if(array==null||length<=0)
{
return 0;
}
if(length==1)
{
return array[0];
}
vector<int> tempArray = array;
for(int i=0;i<length;i++)
{
//后面需要用零来代表抹除数字,所以对0时做特殊处理
if(tempArray[i]==0)
{
continue;
}
for (int j = i+1 ; j<length; j++)
{
if (tempArray[i] != tempArray[j] && tempArray[j] != 0)
{
tempArray[i] = 0;//此处用0代表抹去该数字
tempArray[j] = 0;
break;
}
}
}
for (int i=0;i<length;i++)
{
cout<<tempArray[i]<<" ";
}
cout<<endl;
//找出未被抹去的数字
int result=0;
for (int i=0;i<length;i++)
{
if (tempArray[i] != 0)
{
result=tempArray[i];
break;
}
}
//统计该数字的个数
int times=0;
for(int i=0;i<length;i++)
{
if(result==array[i])
{
times++;
}
}
return 2*times>=length ? result : 0;
}
}
3、排序法
数组排序后,如果符合条件的数存在,则一定是数组中间那个数。
(比如:1,2,2,2,3;或2,2,2,3,4;或2,3,4,4,4等等)
这种方法虽然容易理解,但由于涉及到快排sort,其时间复杂度为O(NlogN)并非最优;