データストリームで不足している番号を特定する


14

セットからペアごとに異なる数のストリームを受け取ります。{ 1 n }n1{1,,n}

ストリームを1回読み取り、ビットのみのメモリを使用するアルゴリズムを使用して、不足している数値を特定するにはどうすればよいですか?O(log2n)

回答:


7

あなたが知っている、及びためで符号化することができるビットこれはメモリと1つのパスで実行できます(見つけてください。これは数値がありません)。 S=nn+1=1n=nn+12 OlognOlognScurrentSumS=nn+12OログnOログnScあなたはrrentSあなたはm

しかし、この問題は、(一定のための一般的なケースで解決することができ):我々は不足している番号を、それらのすべてを見つけます。この場合、合計を計算する代わりに、すべてのののj'st乗の合計を計算します(は欠損数で、は入力数であると仮定します):、K 、Y 、I X 、I 1 J kはX I 、Y Ikkyバツ1jkバツy

=1kバツ=S1=1kバツ2=S2=1kバツk=Sk 1

あなたが計算できることを覚えておいてくださいS1Skするので、単にS1=SyS2=2y2、...

欠落している数字を見つけるには、すべてのx_iを見つけるために1を解く必要があります。バツ

以下を計算できます:

P1=バツP2=バツバツj、...、2 Pk=バツ 2

このため、 P1=S1P2=S12S22、...

しかし、は係数ですが、一意に因数分解できるため、欠落している数値を見つけることができます。 P =PPP=バツバツ1バツバツ2バツバツkP

これらは私の考えではありません。これを読んでください。


1
取得できません(2)。たぶん、あなたが合計の詳細に追加した場合は?DOES欠場?Pk
ラファエル

@Raphaelは、ニュートンのアイデンティティである、私はあなたが計算のアイデアを得ることができ、私の参照wikiページを見ている場合、それぞれだと思い前回によって計算できる、S:単純な公式を覚えて、、すべてのべき乗に同様のアプローチを適用できます。また、私が書いたように、は何かのシグマですが、はがありません。これは、 1つしかないためです。P I P S jの 2 X 1X 2 = X 1 + X 2 2 - X 2 1 + X 2 2P I P K Σ ΠPiPiPSj2x1x2=(x1+x2)2(x12+x22)PiPkΣΠ

それがそうであるかもしれないとして、答えは合理的な程度まで自己完結しているべきです。あなたはいくつかの式を与えるので、それらを完成させてみませんか?
ラファエル

11

上記のコメントから:

ストリームを処理する前に、ビットを割り当てます(はおよびバイナリ表現は、点ごとに排他的です(または)。単純に、これには時間かかります。X = N iは= 1 bのI NI B I NI I ON ログ2nバツ:==1nbnbnOn

ストリームの処理時に、数値読み取るたびに、計算します。ましょうから単一の数でストリームに含まれません。ストリーム全体を読み取った後、 目的の結果が得られます。X = X B I NJ K { 1 N } 、X = N iが= 1 bのI NI I K B 、I NI = B I NK I Kjバツ:=バツbnjk{1n}

x=(i=1nbin(i))(ikbin(i))=bin(k)ik(bin(i)bin(i))=bin(k),

したがって、スペースを使用し、全体的なランタイムは。O(logn)O(n


3
これを真のストリーミングシングルパスアルゴリズムにする簡単な最適化を提案できます。タイムステップでxorにおよび入力が到着します。ストリーム。これには、が事前にわからない場合でも機能させることができるという追加の利点があります割り当てられた1ビットから始めて、必要に応じて割り当てられたスペースを「増やします」。バツbnbnjnバツ
サショニコロフ

0

HdMのソリューションは機能します。それをテストするためにC ++でコーディングしました。私は制限することはできませんvalueにビットを、私はあなたが簡単にビット数が実際に設定されていることをどのようにのみ表示することができますよ。Oログ2n

擬似コードが必要な場合は、排他的()を指定した単純な操作を使用し。折る

行方不明=折る{1N}InputStream

手振りの証明:は入力よりも多くのビットを必要としないため、上記の中間結果は入力の最大ビットビット)を超える必要はありません。は可換であり、。したがって、上記を展開し、ストリームに存在するすべてのデータをペアにすると、一致しない単一の値、欠落している数値のみが残ります。Oログ2nバツバツ=0

#include <iostream>
#include <vector>
#include <cstdlib>
#include <algorithm>

using namespace std;

void find_missing( int const * stream, int len );

int main( int argc, char ** argv )
{
    if( argc < 2 )
    {
        cerr << "Syntax: " << argv[0] << " N" << endl;
        return 1;
    }
    int n = atoi( argv[1] );

    //construct sequence
    vector<int> seq;
    for( int i=1; i <= n; ++i )
        seq.push_back( i );

    //remove a number and remember it
    srand( unsigned(time(0)) );
    int remove = (rand() % n) + 1;
    seq.erase( seq.begin() + (remove - 1) );
    cout << "Removed: " << remove << endl;

    //give the stream a random order
    std::random_shuffle( seq.begin(), seq.end() );

    find_missing( &seq[0], int(seq.size()) );
}

//HdM's solution
void find_missing( int const * stream, int len )
{
    //create initial value of n sequence xor'ed (n == len+1)
    int value = 0;
    for( int i=0; i < (len+1); ++i )
        value = value ^ (i+1);

    //xor all items in stream
    for( int i=0; i < len; ++i, ++stream )
        value = value ^ *stream;

    //what's left is the missing number
    cout << "Found: " << value << endl;
}

3
代わりに、アルゴリズムのみの読み取り可能な(擬似)コードを投稿してください(メインをスキップ)。また、あるレベルでの正当性の証明/引数を含める必要があります。
ラファエル

4
@ edA-qamort-ora-y答えは読者がC ++を知っていることを前提としています。この言語に精通していない人にとっては、見るべきものは何もありません。関連するパッセージを見つけることと、それが何をしているのかを理解することの両方が課題です。読み取り可能な擬似コードは、これをより良い答えにします。C ++は、コンピューターサイエンスサイトではあまり役に立ちません。
ジル「SO-悪であるのをやめる」

3
私の答えが役に立たないことが判明した場合、人々はそれに投票する必要はありません。
edA-qa mort-ora-y

2
実際にC ++コードを記述してテストするのに時間を割いて+1。残念ながら、他の人が指摘したように、それはそうではありません。それでもあなたはこれに努力します!
ジュリアンレボット

9
私はこの答えの要点を理解していません。非常に単純で明らかに非常に効率的な他の誰かのソリューションを採用し、それを「テスト」してください。なぜテストが必要ですか?これは、コンピューターをテストすることで数字を正しく追加するようなものです。そして、あなたのコードにも決して些細なことはありません。
サショニコロフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.