Determina il numero mancante nel flusso di dati


14

Riceviamo un flusso di numeri diversi a coppie dall'insieme .{ 1 , , n }n1{1,,n}

Come posso determinare il numero mancante con un algoritmo che legge il flusso una volta e usa una memoria di soli bit ?O(log2n)

Risposte:


7

Sai e perché potrebbe essere codificato in bit questo può essere fatto nella memoria O (\ log n) e in un percorso (basta trovare S - \ mathrm {currentSum} , questo è il numero mancante). S=n(n+1)i=1ni=n(n+1)2 O(log(n))O(logn)S-currentSumS=n(n+1)2O(log(n))O(logn)ScurrentSum

Ma questo problema potrebbe essere risolto nel caso generale (per costante k ): abbiamo k numeri mancanti, scoprili tutti. In questo caso invece di calcolare solo la somma di yi , calcola la somma della j'st potenza di xi per tutti 1jk (ho assunto che xi manchi numeri mancanti e yi sia numeri di input):

i=1kxi=S1,i=1kxi2=S2,i=1kxik=Sk (1)

Ricorda che puoi calcolare S1,...Sk semplicemente, perché S1=Syi , S2=i2yi2 , ...

Ora per trovare i numeri mancanti dovresti risolvere (1) per trovare tutti xi .

Puoi calcolare:

P1=xi , P2=xixj , ..., Pk=xi (2) .

Per questo ricorda che P1=S1 , P2=S12S22 , ...

Ma è coefficienti di ma potrebbe essere considerato in modo univoco, quindi puoi trovare i numeri mancanti.PiP=(xx1)(xx2)(xxk)P

Questi non sono i miei pensieri; Leggere questo .


1
Non capisco (2). Forse se hai aggiunto i dettagli delle somme? Fa sbaglia un ? Pk
Raffaello

@Raphael, sono le identità di Newton, penso che se dai un'occhiata alla mia pagina wiki di riferimento puoi avere l'idea del calcolo, ogni potrebbe essere calcolato dai precedenti s, , ricorda la formula semplice: , puoi applicare un approccio simile a tutti i poteri. Anche come ho scritto è sigma di qualcosa, ma non ha alcun , perché c'è solo un . PiPiPSj2x1x2=(x1+x2)2(x12+x22)PiPkΣΠ

Comunque sia, le risposte dovrebbero essere autosufficienti in misura ragionevole. Dai alcune formule, quindi perché non renderle complete?
Raffaello

11

Dal commento sopra:

Prima di elaborare il flusso, allocare bit, in cui si scrive ( è il la rappresentazione binaria di e è in senso esclusivo o). Ingenuamente, ciò richiede tempo.log2nx:=i=1nbin(i)bin(i)iO(n)

Dopo aver elaborato il flusso, ogni volta che si legge un numero , calcolare . Sia il numero singolo di che non è incluso nello stream. Dopo aver letto l'intero flusso, abbiamo producendo il risultato desiderato.jx:=xbin(j)k{1,...n}

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

Quindi, abbiamo usato lo spazio e abbiamo un tempo di esecuzione complessivo di .O(logn)O(n)


3
posso suggerire una facile ottimizzazione che renda questo un vero algoritmo single-pass in streaming: al momento passo , xor con e con l'input che è arrivato sul streaming. questo ha l'ulteriore vantaggio di poterlo far funzionare anche se non è noto in anticipo: basta iniziare con un singolo bit allocato per "aumentare" lo spazio allocato secondo necessità. ixbin(i)bin(j)nx
Sasho Nikolov,

0

La soluzione di HdM funziona. L'ho codificato in C ++ per testarlo. Non posso limitare i bit valuea , ma sono sicuro che puoi facilmente mostrare come è impostato solo quel numero di bit.O(log2n)

Per coloro che desiderano uno pseudo codice, utilizzare una semplice operazione di con esclusivo o ( ):fold

Missing=fold(,{1,,N}InputStream)

Hand-wavey proof: A non richiede mai più bit del suo input, quindi ne consegue che nessun risultato intermedio sopra richiede più dei bit massimi dell'input (quindi O ( log 2 n ) bit). è commutativo e x x = 0 , quindi se si espande quanto sopra e si accoppiano tutti i dati presenti nello stream, si rimarrà solo con un singolo valore non corrispondente, il numero mancante.O(log2n)xx=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
Per favore, inserisci il codice (pseudo) leggibile solo dell'algoritmo (salta principale). Inoltre, dovrebbe essere inclusa una prova / argomento di correttezza a un certo livello.
Raffaello

4
@ edA-qamort-ora-y La tua risposta presuppone che il lettore conosca il C ++. Per qualcuno che non ha familiarità con questa lingua, non c'è nulla da vedere: sia trovare il passaggio pertinente sia capire cosa sta facendo sono una sfida. Lo pseudocodice leggibile renderebbe questa una risposta migliore. Il C ++ non è davvero utile su un sito di informatica.
Gilles 'SO- smetti di essere malvagio'

3
Se la mia risposta dimostra di non essere utile, le persone non devono votare per questo.
edA-qa mort-ora-y

2
+1 per aver dedicato del tempo a scrivere codice C ++ e testarlo. Sfortunatamente, come altri hanno sottolineato, non è così. Ti sforzi ancora in questo!
Julien Lebot,

9
Non capisco il punto di questa risposta: prendi la soluzione di qualcun altro, che è molto semplice e ovviamente molto efficiente, e la "collaudi". Perché sono necessari i test? È come testare il tuo computer aggiungendo i numeri correttamente. E non c'è nulla di non banale nemmeno nel tuo codice.
Sasho Nikolov,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.