含有n个元素的序列,多数元素指出现次数多于n/2的元素。
不漂亮的算法:
朴素:依次将每个元素同其他元素比较,统计其出现次数,Θ(n2)。
排序并寻找中间元素:排序这一块就是O(nlogn),中间元素可能是多数元素,还需要扫一遍序列确定,Θ(n)。
漂亮的算法:
这是一个Θ(n)的算法,基于下面这个结论:
在原序列中去除两个不同的元素后,那么在原序列中的多数元素在新序列中还是多数元素。
仔细理解选择候选者元素的candidate()方法,这一结论的作用就在这里体现。
基本思路:
寻找候选者(唯一的一个可能为多数元素的值,相当于中间元素)的过程:
(1)计数器count置1,另c=A[1];
(2)从A[2]开始向后扫描,
for j=2 to n
若a[j]与c相等,则count++;
若a[j]与c不等,则count—
若count==0,则对A[j+1...n]寻找多数元素候选者(这里的情况就是前面有几对不相等的数,于是就统统去掉,在剩余的数中寻找候选者,结论用在这里)。
If j=n then return c(返回可能的候选者c)
end for
得到候选者元素后,我们只需要扫一遍序列,确认候选元素是否为多数元素就好了。
这两个过程都是Θ(n)的。
伪代码:
C++代码:
- #include<stdio.h>
- #include<stdlib.h>
-
- int candidate(int p[],int m,int n){
- int j = m;
- int c = p[m];
- int count = 1;
- while( j < n&&count > 0){
- j ++;
- if(p[m] == c) count ++;
- else count --;
- }
- if(j == n) return c;
- else return candidate(p,j + 1,n);
- }
-
-
- int main(){
- int i;
- int n;
- int c;
- int *p;
- while(scanf("%d",&n)!=EOF)
- {
- p = (int *)malloc(n*sizeof(int));
- for(i = 0;i < n;i ++){
- scanf("%d",&p[i]);
- }
- c = candidate(p,0,n);
- int count = 0;
- for(i = 0;i < n;i ++){
- if(p[i] == c) count ++;
- }
- if(count > n/2)
- printf("%d\n",c);
- }
- system("pause");
- return 0;
- }<span style="color: rgb(54, 46, 43); font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
推导出迭代版本:
- #include<stdio.h>
- #include<stdlib.h>
-
- int candidate(int p[],int n){
- int j = 0;
- int c;
- int count;
- while(j != n){
- c = p[j];
- count = 1;
- while( j < n&&count > 0){
- j ++;
- if(p[j] == c) count ++;
- else count --;
- }
- if(j == n) return c;
- else j ++;
- }
- }
-
- int main(){
- int i;
- int n;
- int c;
- int *p;
- while(scanf("%d",&n)!=EOF)
- {
- p = (int *)malloc(n*sizeof(int));
- for(i = 0;i < n;i ++){
- scanf("%d",&p[i]);
- }
- c = candidate(p,n);
- int count = 0;
- for(i = 0;i < n;i ++){
- if(p[i] == c) count ++;
- }
- if(count > n/2)
- printf("%d\n",c);
-
- }
- return 0;
- }