问题要求:
数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。
参考资料:编程之美2.3 寻找发帖水王
问题分析:
方法1 对数组排序,然后顺次查找其中最多的;
方法2 对数组排序,最中间一个肯定为要找的数字,时间复杂度O(NlogN);
方法3 每次消去数组中两个不同的数,最后剩下的肯定为要找的数字,时间复杂度O(N).
方法3代码1如下,以下是图解代码1
代码实现:
//代码1
#include <stdio.h>
int Find(int* ID, int N);
int main(void)
{
int ID[30] = {5,6,7,1,2,1,2,1,2,3,3,4,3,2,1,3,2,1,2,1,3,1,1,1,1,1};
printf("水王id: %d\n",Find(ID,30));
return 0;
}
int Find(int* ID, int N)
{
int candidate;
int nTimes, i;
for(i = nTimes = 0; i < N; i++)
{
if(nTimes == 0)
{
candidate = ID[i], nTimes = 1;
}
else
{
if(candidate == ID[i])
nTimes++;
else
nTimes--;
}
}
return candidate;
}
扩展问题1:
如果改为该数字长度为数组长度的一半,又该如何求?
问题分析:
先消掉3个不同的id,再使用代码1的方法求解。因为消除3个不同id时,水王id最多消除一个,则,这样之后水王id个数就大于总数的一半了,就变成原问题了。
代码实现:
#include <stdio.h>
int Find(int* ID, int N);
int main(void)
{
int ID[6] = {2,1,2,1,3,1};
printf("水王id: %d\n",Find(ID,6));
return 0;
}
int Find(int* ID, int N)
{
int candidate;
int nTimes = 0, i;
int flag = 0;
int del[3];
del[0] = ID[0];
for(i = 1; i < N; i++)
{
if((ID[i] != del[0]) && (flag == 0))
{
del[1] = ID[i];
flag = 1;
continue;
}
if((ID[i] != del[0]) && (ID[i] != del[1]) && (flag == 1))
{
flag = 2;
continue;
}
if(nTimes == 0)
{
candidate = ID[i], nTimes = 1;
}
else
{
if(candidate == ID[i])
nTimes++;
else
nTimes--;
}
}
return candidate;
}
扩展问题2:
如果数组中的3个数字个数都分别超过了数组长度的1/4,又该如何查出它们?
问题分析:
每次绑定三个id,同时加减。
代码实现:
#include <stdio.h>
void Find(int* ID, int N);
int main(void)
{
int ID[] = {5,6,7,1,2,1,2,1,2,3,3,4,3,2,1,3,2,1,2,1,3};
Find(ID,21);
return 0;
}
void Find(int* ID, int N)
{
int nTimes[3], i;
int candidate[3];
nTimes[0]=nTimes[1]=nTimes[2]=0;
candidate[0]=candidate[1]=candidate[2]=-1;
for(i = 0; i < N; i++)
{
if(ID[i]==candidate[0])//这几个并列的思想很重要,好好想想
{
nTimes[0]++;
}
else if(ID[i]==candidate[1])
{
nTimes[1]++;
}
else if(ID[i]==candidate[2])
{
nTimes[2]++;
}
else if(nTimes[0]==0)
{
nTimes[0]=1;
candidate[0]=ID[i];
}
else if(nTimes[1]==0)
{
nTimes[1]=1;
candidate[1]=ID[i];
}
else if(nTimes[2]==0)
{
nTimes[2]=1;
candidate[2]=ID[i];
}
else//新的id和已选的三个id不同的时候,让已选的三个id同时-1
{
nTimes[0]--;
nTimes[1]--;
nTimes[2]--;
}
}
printf("id: %d %d %d\n",candidate[0],candidate[1],candidate[2]);
printf("times:%d %d %d\n",nTimes[0],nTimes[1],nTimes[2]);
return;
}