데이터 스트림에서 누락 된 숫자 결정


14

집합 에서 쌍으로 다른 숫자 의 스트림을받습니다 .{ 1 , … , n }n−1{1,…,n}

스트림을 한 번 읽고 비트 의 메모리 만 사용하는 알고리즘으로 누락 된 숫자를 어떻게 확인할 수 있습니까?O(log2⁡n)

답변:


7

알다시피 , 때문에 부호화 될 수있다 비트 이것은 메모리와 하나의 경로에서 수행 할 수 있습니다 ( 찾으십시오 .이 숫자는 누락되었습니다). S=n(n+1)∑i=1ni=n(n+1)2 O(로그(n))O(로그n)S−currentSumS=n(n+1)2O(log⁡(n))O(log⁡n)S−currentSum

그러나이 문제는 일반적인 경우 (상수 ) 에서 해결할 수 있습니다 . 우리는 누락 된 숫자 가 있으며 모두 알아냅니다. 이 경우 합을 계산하는 대신 모든 대해 의 j'st 거듭 제곱의 합을 계산하십시오 ( 는 누락 된 숫자이고 는 입력 숫자 라고 가정 합니다).k y i x i 1 ≤ j ≤ k x i y ikkyixi1≤j≤kxiyi

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

, , ... 이므로 간단히 계산할 수 있습니다 .S 1 = S − ∑ y i S 2 = ∑ i 2 − ∑ y 2 iS1,...SkS1=S−∑yiS2=∑i2−∑yi2

이제 누락 된 숫자 를 찾으려면 을 풀고 모든 를 찾으십시오 .x 나는(1)xi

다음을 계산할 수 있습니다.

P 2 = ∑ x i ⋅ x j P k = ∏ x i ( 2 )P1=∑xi , , ..., .P2=∑xi⋅xjPk=∏xi (2)

이를 위해 기억이 , , ...P1=S1P2=S12−S22

그러나 는 계수 이지만 는 고유하게 인수 분해 되므로 누락 된 숫자를 찾을 수 있습니다.PiP=(x−x1)⋅(x−x2)⋯(x−xk)P

이것들은 내 생각이 아니다. 이것을 읽으십시오 .


1
나는 얻지 못했다 (2). 아마도 당신이 합계의 세부 사항을 추가 한 경우? 가 그리워 합니까 ? Pk∑
— Raphael

@Raphael, 는 Newton의 정체성입니다. 참조 된 Wiki 페이지를 보면 계산 아이디어를 얻을 수 있다고 생각합니다. 각 는 이전 , 로 계산할 수 있습니다 . 간단한 공식을 기억하십시오 이면 모든 거듭 제곱에 유사한 접근 방식을 적용 할 수 있습니다. 또한 는 무언가의 시그마이지만, 에는 가 없습니다 . 가 하나뿐이기 때문입니다 . PiPiPSj2⋅x1⋅x2=(x1+x2)2−(x12+x22)PiPkΣΠ

가능한 한 대답은 합리적인 수준으로 자체적으로 포함되어야합니다. 당신은 몇 가지 공식을 제공, 왜 그들을 완료하지?
— Raphael

11

위의 의견에서 :

스트림을 처리하기 전에, 할당 가 연락하는 비트, X : = ⨁ N I = 1 B 나 N ( I ) ( b를 i가 N ( 나 ) 의 이진 표현 난 과 ⊕ 이다 점별 배타적을 또는). 순진하게, 이것은 O ( n ) 시간 이 걸린다 .⌈log2⁡n⌉x:=⨁i=1nbin(i)bin(i)i⊕O(n)

하나는 다수의 스트림마다 판독 처리시 , 컴퓨팅 X : = X ⊕ B 나 N ( J ) . k 는 { 1 , 의 단일 숫자라고 하자 . . . n } 스트림에 포함되지 않습니다. 전체 스트림을 읽은 후 x = ( n ⨁ i = 1 b i n ( i ) ) ⊕ ( ⨁ i ≠ k bjx:=x⊕bin(j)k{1,...n} 원하는 결과를 얻었다.

x=(⨁i=1nbin(i))⊕(⨁i≠kbin(i))=bin(k)⊕⨁i≠k(bin(i)⊕bin(i))=bin(k),

따라서, 우리가 사용 공간 및 전반적인 실행이 O ( N을 ) .O(log⁡n)O(n)


3
이것을 진정한 스트리밍 단일 패스 알고리즘으로 만드는 쉬운 최적화를 제안 할 수 있습니다 : 시간 단계 , x 또는 x with b i n ( i ) 및 입력 b i n ( j ) 을 사용하여 스트림에 도착했습니다. 이것은 n을 미리 알지 못하는 경우에도 작동하도록 할 수있는 추가 이점이 있습니다 . x에 할당 된 단일 비트로 시작하고 필요에 따라 할당 된 공간을 "증가"하면됩니다. 나는엑스bin(i)bin(j)nx
— Sasho Nikolov

0

HdM의 솔루션이 작동합니다. 테스트하기 위해 C ++로 코딩했습니다. 나는를 제한 할 수 없습니다 value에 비트,하지만 난 당신이 쉽게 비트의 수는 실제로 설정되어 있는지 방법만을 보여줄 수 있어요.O(log2⁡n)

의사 코드를 원하는 경우 독점 또는 ( ⊕ ) 로 간단한 작업을 사용하십시오 .fold⊕

Missing=fold(⊕,{1,…,N}∪InputStream)

손파 방지 : A 는 입력보다 더 많은 비트를 필요로하지 않으므로, 위의 중간 결과가 입력의 최대 비트 ( O ( log 2 n ) 비트 이상)를 요구하지 않습니다. ⊕ 는 교환 적이며 x ⊕ x = 0 이므로 위를 확장하고 스트림에 존재하는 모든 데이터를 쌍으로 묶으면 일치하지 않는 단일 값인 누락 된 숫자 만 남게됩니다.⊕O(log2⁡n)⊕x⊕x=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
대신 알고리즘의 읽을 수있는 (의사) 코드를 대신 게시하십시오 (기본 건너 뛰기). 또한, 어느 정도의 정확성 증명 / 인수가 포함되어야합니다.
— Raphael

4
@ edA-qamort-ora-y 귀하의 답변은 독자가 C ++을 알고 있다고 가정합니다. 이 언어에 익숙하지 않은 사람에게는 볼 내용이 없습니다. 관련 구절을 찾고 그 내용을 이해하는 것은 어려운 일입니다. 읽을 수있는 의사 코드는 이것이 더 나은 대답이 될 것입니다. C ++은 컴퓨터 과학 사이트에서 실제로 유용하지 않습니다.
— Gilles 'SO- 악마 그만'

3
제 답변이 유용하지 않다면 사람들은 투표 할 필요가 없습니다.
— edA-qa mort-ora-y

2
실제로 C ++ 코드를 작성하고 테스트하는 데 시간이 걸리는 +1 불행히도 다른 사람들이 지적했듯이 그렇지 않습니다. 아직도 당신은 이것에 노력을 넣어!
— Julien Lebot

9
나는이 대답의 요점을 알 수 없다. 당신은 다른 사람의 해결책을 취한다. 그것은 매우 간단하고 명백히 매우 효율적이며 그것을 "테스트"한다. 왜 테스트가 필요한가요? 이것은 컴퓨터가 숫자를 올바르게 추가하는지 테스트하는 것과 같습니다. 그리고 코드에도 사소한 것이 없습니다.
— Sasho Nikolov
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.