问题要求:
数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。
参考资料:编程之美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] = {1,2,3,4,1,1,2,1,1,1,12,1}; printf("水王id: %d ",Find(ID,12)); 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 ",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 ",candidate[0],candidate[1],candidate[2]); printf("times:%d %d %d ",nTimes[0],nTimes[1],nTimes[2]); return; }