问题:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
方法一:
定义一个关联容器map,将元素依次塞入map中,对每个元素w依次检验出现的个数,w.first为元素值,w.second为对应元素个数,如果个数大于长度的一半,就返回
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers)
{
int len=numbers.size();
map<int,size_t>result; //size_t一般用来表示一种计数
auto tmp=numbers.begin();
for(;tmp<numbers.end();tmp++) //end指向尾元素之后的位置,区间为[begin,end)
result[*tmp]++; //解引用迭代器,得到了元素
for(auto &w : result)
{
if(w.second>len/2)
return w.first;
}
return 0;
}
};
方法二:
对所有的元素进行排序,将所有元素遍历一遍,计算每种元素的个数,若当前元素的个数大于前面的统计结果,将结果刷新
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers)
{
int len = numbers.size();
sort(numbers.begin(), numbers.end()); //对元素进行排序
int num = 0, resultnum = 0; //num为计数器,resultnum为元素数最多的元素的个数
int result = *numbers.begin(); //结果初始化为第一个元素
auto tmp = numbers.begin();
while (tmp < numbers.end() - 1) //下面需要对tmp++,所以tmp最大指到倒数第二个元素
{//比较当前元素与下一个元素是否相等,相等,将计数器加1,同时也实现了元素后移
if (*tmp == *(++tmp))
num++;
else
{
if (num > resultnum) //当前元素个数大于前面的的统计结果
{
resultnum = num; //刷新元素个数最大值
result = *(tmp-1); //前面比较元素相等时,将tmp后移了一位,这里需要减1
}
num = 0; //重置计数器
}
}
if (resultnum + 1 > len / 2) //resultnum计算结果为对应元素个数减1
return result;
return 0;
}
};
当然也可以用for循环代替while循环
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers)
{
int len = numbers.size();
sort(numbers.begin(), numbers.end()); //对元素进行排序
int num = 0, resultnum = 0; //num为计数器,resultnum为元素数最多的元素的个数
int result = *numbers.begin(); //结果初始化为第一个元素
//下面需要对tmp+1,所以tmp最大指到倒数第二个元素
for(auto tmp = numbers.begin();tmp < numbers.end() - 1;tmp++)
{//比较当前元素与下一个元素是否相等,相等,将计数器加1
if (*tmp == *(tmp+1))
num++;
else
{
if (num > resultnum) //当前元素个数大于前面的的统计结果
{
resultnum = num; //刷新元素个数最大值
result = *(tmp);
}
num = 0;
}
}
if (resultnum + 1 > len / 2) //resultnum计算结果为对应元素个数减1
return result;
return 0;
}
};
对于vector的操作,不仅可以解引用迭代器来获取元素,也可以通过下表来获取元素,如vector类型的变量numbers,numbers[0]表示第一个元素,下标从0开始;
对所有元素进行排序,则相等的元素将会在相邻的位置。设置一个临时量等于每一种元素的第一个元素,循环统计这种元素的个数;若后面有数量更大的元素,刷新这个记录,统计出最大个数的元素,如果数量大于总长度的一般,返回这个元素
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers)
{
int len=numbers.size();
if(len==0)
return 0;
sort(numbers.begin(),numbers.end());
int num=0,resultnum=0;
int result=numbers[0];
int tmp=numbers[0];
//若容器中只有一种元素,则不会出现下面循环中else,即不会更新result与resultnum
if(numbers[0]==numbers[len-1])
return numbers[0];
for(int i=0;i<len;i++)
{
if(tmp==numbers[i])
num++;
else
{
if(num>resultnum)
{
resultnum=num;
result=tmp;
}
num=1;
tmp=numbers[i];
}
}
if(resultnum>len/2)
return result;
return 0;
}
};
方法三:
数组排序后,如果符合条件的数存在,则一定是数组中间那个数。(比如:1,2,2,2,3;或2,2,2,3,4;或2,3,4,4,4等等)
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers)
{
int len = numbers.size();
if (len == 0)
return 0;
sort(numbers.begin(),numbers.end()); //排序
int count=0;
int middle = numbers[len/2]; //取中间值,注意,中间值是第len/2+1个,但下标是len/2
for (int i = 0; i < len; i++)
{
if (middle==numbers[i])
count++;
}
if(count>len/2)
return middle;
return 0;
}
};
时间复杂度分析:涉及到快排sort,时间复杂度为O(NlogN);
方法四:
采用用户“分形叶”思路(注意到目标数超过数组长度的一半,数组同时去掉两个不同的数字,到最后剩下的就是目标数),如果没有超过数组长度的一半的目标数,则剩下某一个,所以最后要统计剩下的这个数的个数,大于数组长度一半,则返回该数,不大于,返回0。
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers)
{
int len = numbers.size();
if (len == 0)
return 0;
int count = 1;
int tmp = numbers[0];
for (int i = 1; i < len; i++)
{
if (count == 0)
{
tmp=numbers[i];
count=1;
}
else if (tmp==numbers[i])
count++;
else
count--;
}
int result=tmp;
int num=0;
for (int i = 0; i < len; i++)
if(result==numbers[i])
num++;
if(num>len/2)
return result;
return 0;
}
};
时间复杂度分析:O(n)