在我阅读此内容时(Find the most common entry in an array),建议Boyer and Moore's Linear Time Voting Algorithm。
如果您点击该站点的链接,则会逐步说明该算法的工作原理。对于给定的序列,AAACCBBCCCBCC
它提供了正确的解决方案。
当我们将指针向前移动时 元素e:
- 如果计数器为0,我们将当前候选设置为e并设置 反对1.
- 如果计数器不为0,我们递增或递减计数器 根据e是否是当前的 候选人。
当我们完成时,当前 候选人是多数元素,如果 占多数。
如果我在一张以AAACCBB
作为输入的纸张上使用此算法,建议的候选人将变为B 显然是错误的。
我认为,有两种可能性
AAACCBBCCCBCC
以外的任何其他算法,完全不称职,应该当场解雇(疑问)。注意:这是来自Niek Sanders的C++ implementation of the algorithm。我相信他正确地实现了这个想法,因此它有同样的问题(或者不是吗?)。
答案 0 :(得分:45)
该算法仅在集合占多数时才有效 - 超过一半的元素相同。您的示例中的AAACCBB
没有这样的多数。最常见的字母出现3次,字符串长度为7.
答案 1 :(得分:27)
小但是对其他解释的重要补充。摩尔的投票算法有两部分 -
运行摩尔投票算法的第一部分仅为多数元素提供候选。请注意这里的“候选人”一词。
在第二部分中,我们需要再次遍历数组以确定此候选项是否出现最大次数(即大于/ 2次)。
第一次迭代是找到候选人&第二次迭代是检查给定数组中该元素是否多数出现。
所以时间复杂度是:O(n) + O(n) ≈ O(n)
答案 2 :(得分:7)
从第一个链接的SO问题:
具有属性,即数组中超过一半的条目等于N
来自Boyer和Moore页面:
如果存在这样的元素
,则序列的哪个元素占多数
这两种算法都明确假设一个元素出现至少N / 2次。 (特别注意“多数”与“最常见”不同。)
答案 3 :(得分:0)
我为这个算法编写了一个C ++代码
char find_more_than_half_shown_number(char* arr, int len){
int i=0;
std::vector<int> vec;
while(i<len){
if(vec.empty()){
vec.push_back(arr[i]);
vec.push_back(1);
}else if(vec[0]==arr[i]){
vec[1]++;
}else if(vec[0]!=arr[i]&&vec[1]!=0){
vec[1]--;
}else{
vec[0]=arr[i];
}
i++;
}
int tmp_count=0;
for(int i=0;i<len;i++){
if(arr[i]==vec[0])
tmp_count++;
}
if(tmp_count>=(len+1)/2)
return vec[0];
else
return -1;
}
,主要功能如下:
int main(int argc, const char * argv[])
{
char arr[]={'A','A','A','C','C','B','B','C','C','C','B','C','C'};
int len=sizeof(arr)/sizeof(char);
char rest_num=find_more_than_half_shown_number(arr,len);
std::cout << "rest_num="<<rest_num<<std::endl;
return 0;
}
答案 4 :(得分:0)
当测试用例是&#34; AAACCBB&#34;时,该集合没有多数。因为&#34; AAACCBB&#34;的长度不会超过3次。是7。
以下是&#34; Boyer和Moore的线性时间投票算法&#34;的代码:
int Voting(vector<int> &num) {
int count = 0;
int candidate;
for(int i = 0; i < num.size(); ++i) {
if(count == 0) {
candidate = num[i];
count = 1;
}
else
count = (candidate == num[i]) ? ++count : --count;
}
return candidate;
}