首页 > 代码库 > 数组中超过出现次数一半的数字 【微软面试100题 第七十四题】

数组中超过出现次数一半的数字 【微软面试100题 第七十四题】

问题要求:

  数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。

  参考资料:编程之美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;}

 

数组中超过出现次数一半的数字 【微软面试100题 第七十四题】