题目六:
给定一个整型数组,找出主元素,它在数组中的出现次数严格大于数组元素个数的二分之一。
注意事项
You may assume that the array is non-empty and the majority number always exist in the array。
样例
给出数组[1,1,1,1,2,2,2],返回 1
代码:
int majorityNumber(vector<int> &nums) {
// write your code here
int i,l,t;
int flag = 0;
int size = nums.size()/2;
if(nums.size()>=2)
{
S s[size];
S *p,*q;
for(i=0;i<size;i++)
{
s[i].num = 0;
s[i].time = 0;
s[i].next = NULL;
}
for(i=0;i<nums.size();i++)
{
flag = 0;
l = nums[i]%size;
if(s[l].time == 0)
{
s[l].num = nums[i];
s[l].time++;
t = s[l].time;
}
else
{
if(s[l].num == nums[i])
{
s[l].time++;
t = s[l].time;
}
else
{
p = &s[l];
q = p->next;
while(p&&q)
{
if(p->num == nums[i])
{
p->time++;
t = p->time;
flag = 1;
break;
}
p = p->next;
q = q->next;
}
if(flag == 0)
{
q = new S;
q->num = nums[i];
q->time = 1;
q->next = NULL;
p->next = q;
t = 1;
}
}
}
if(t>size)
{
t = nums[i];
break;
}
}
return t;
}
else
{
return nums[0];
}
}
这个是我自己的思路,Accepted以后我还是挺震惊的。先说说我的想法吧,我用了hash表的思路。因为要求时间复杂度是O(n),所以首先考虑的是能够不需要遍历直接就能确定该元素在数组中出现的频度的方法,于是就想到了用hash表的除留余数法,经过计算直接获得元素的位置,用拉链法处理冲突,表长为nums长度的一半,然后建立一个结构体存储频率和元素,每遍历一个元素,判断其频率是否大于size,大于则直接返回该元素,否则继续。hash表只能在nums长度大于等于2时建立,如果nums长度等于一,直接返回元素
不可否认得是这确实是一个笨笨的算法,但是作为目前为止第一个自己独立想出来并且Accepted的题目我还是很开心的。
以下是我百度找到的一个更简单的也是用的最多的算法,咳咳,老脸一红。
int majorityNumber(vector<int> nums)
{
int cnt = 0;
int result = 0;
for (int i = 0; i < nums.size(); i++)
{
if (cnt == 0)
{
result = nums[i];
cnt++;
} else
{
if (result != nums[i])
{
cnt--;
} else
{
cnt++;
}
}
}
return result;
}
思路是把数组中的数据分成两种,一种是主元素,一种是非主元素。当cnt为0说明无候选主元素,此时的nums[i]赋给主元素候选result,如果cnt不为0,说明有候选主元素,如果当前元素与result不同,cnt--,原因是主元素严格大于nums.size()/2,当有一个元素与result不同时,此元素作为主元素在数组中出现的频度就少1,可以理解成它是主元素的可能性就少了,最后遍历完毕以后,cnt必然会大于等于1。假设数组是【1,1,1,1,2,2,2】,cnt初始为0,result为0,在运行到第四(计数器i=3)个元素时(最后一个1)的时候,cnt=4,result = 1;i=4时,cnt=3,result=1;i=5时,cnt=2,result=1;i=6时,cnt=1,result=1;程序结束。