web-dev-qa-db-ja.com

線形時間投票アルゴリズム。わからない

私がこれを読んでいたとき( 配列内の最も一般的なエントリを見つける )、 ボイヤーとムーアの線形時間投票アルゴリズム が提案されました。

サイトへのリンクをたどると、アルゴリズムがどのように機能するかを段階的に説明しています。与えられたシーケンスに対して、AAACCBBCCCBCCは正しい解を示します。

ポインタを要素e上で前方に移動すると:

  • カウンターが0の場合、現在の候補をeに設定し、カウンターを1に設定します。
  • カウンターが0でない場合、eが現在の候補であるかどうかに応じて、カウンターをインクリメントまたはデクリメントします。

完了したら、過半数がある場合、現在の候補が過半数の要素になります。

入力としてAAACCBBを使用してこのアルゴリズムを紙に使用すると、提案された候補はBになり、明らかに間違っています。

私が見るように、2つの可能性があります

  1. 作者はAAACCBBCCCBCC以外でアルゴリズムを試したことがなく、完全に無能であり、その場で解雇する必要があります(doubtfull)
  2. 私は明らかに何かが欠けています、Stackoverflowから禁止されなければならず、ロジックに関係するものに再び触れることは決して許されません。

注:これは、Niek Sandersの アルゴリズムのC++実装 です。彼はそのアイデアを正しく実行したので、同じ問題を抱えていると思います(またはそうではありませんか?)。

42

アルゴリズムは、セットに過半数(要素の半分以上が同じ)がある場合にのみ機能します。あなたの例のAAACCBBにはそのような過半数はありません。最も頻繁な文字は3回出現し、文字列の長さは7です。

45
Rafał Dowgird

小さいですが、他の説明への重要な追加。ムーアの投票アルゴリズムには2つの部分があります-

  1. ムーアの投票アルゴリズムを実行する最初の部分候補のみを提供します多数決要素。ここで「候補」という言葉に注目してください。

  2. 2番目の部分では、この候補が最大回数(つまり、サイズ/ 2回以上)発生するかどうかを判断するために、配列をもう一度繰り返す必要があります。

最初の反復は候補を見つけることであり、2番目の反復はこの要素が指定された配列で大部分の時間発生するかどうかを確認することです。

したがって、時間計算量は次のようになります。O(n) + O(n) ≈ O(n)

28

最初にリンクされたSO質問から:

配列内のエントリの半分以上がNに等しいという特性を持つ

ボイヤーとムーアのページから:

そのような要素がある場合、シーケンスのどの要素が過半数であるか

これらのアルゴリズムは両方とも、1つの要素が発生することを明示的に想定しています少なくともN/2回。 (特に、「多数派」は「最も一般的」と同じではないことに注意してください。)

7
j_random_hacker

このアルゴリズムの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;
}
0
feliciafay

テストケースが「AAACCBB」の場合、セットには過半数がありません。 「AAACCBB」の長さが7であるため、要素が3回以上発生しないためです。

「ボイヤーとムーアの線形時間投票アルゴリズム」のコードは次のとおりです。

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;
    }
0
Peter Rui