问题:其实问题可以简单的说:有一个数组,数组中的某个元素出现的次数超过N/2。问有没有很好的方法快速找到这个元素。
解析:如:char ID[5] = { ‘a’,‘b’,‘a’,‘c’,‘a’};a的出现次数为3。一个很高效的方法就是:当两个元素不相同时就把这两个元素都删除,这样最后剩下的就是要找的元素,当然不一定是真的删除。
#ifndef _2_3_TANGO_H_ #define _2_3_TANGO_H_ //2.3寻找发帖水王 p129 #include <iostream> //本题目的含义是,在一个序列中寻找出现次数最多的id,如a,a,b,c,a,b,a,a 当然a出现次数最多 //如果遍历的话要n^2的复杂度,如果排序的话也要n*logn的时间,如何在n的时间内找到呢? using namespace std; void TangoFind(char* arrID, int size) { char candidate; int nTimes = 0;//元素出现次数 for (int i = 0; i < size; ++i)//如果有两个元素不同,则删除这两个元素,当然不是真的删除 { if (0 == nTimes)//记录某个元素和其它元素不同的次数 { candidate = arrID[i];//如果nTimes为0,则表明 在这之前的元素 如a,b,b,c有偶数个不同对 出现,当然都删除 } else { if (candidate == arrID[i])//如果这个元素又出现 则加1 { nTimes++; } else//如果这个元素没有出现,就是当前的与它不同 就-- { nTimes--; } } } cout<<"candidate="<<candidate<<endl; } #endif//_2_3_TANGO_H_
扩展问题:着Tango的发展,管理员发现,“超级水王”没有了。统计结果表明,有3个发帖很多的ID,他们的发帖数目都超 过了帖子总数目N的1/4。你能从发帖ID列表中快速找出他们的ID吗?
关键想法是:先记录3个不的元素,然后再计算下一个元素是否出现在已经记录的3个元素中,如果有则相应的加1,如果没有则3个元素都减1.
int a[] = {1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,5,6,7,9}; int aTimes=0; int bTimes=0; int cTimes=0; int aCur=0; int bCur=0; int cCur=0; //int cur=0; for (int i = 0; i < 20; i++) { if (aTimes ==0) { aCur = a[i]; aTimes = 1; } else { if (aCur == a[i]) { aTimes++; } else { if (bTimes == 0) { bCur = a[i]; bTimes = 1; } else { if (bCur == a[i]) { bTimes++; } else { if (cTimes == 0) { cCur = a[i]; cTimes = 1; } else { if (cCur == a[i]) { cTimes++; } else { aTimes--; bTimes--; cTimes--; } } } } } } } cout<<aCur<<" "<<bCur<<" "<<cCur<<endl; }
结果为:1 2 3。当然我们发现,有3个元素都超过了总数的1/4,那么这3个元素的总和超过了3/4,我们可以用一个桶来操作,桶的大小为(1/4)*N +3。或者用map关联容器也可以。