Xác định số bị thiếu trong luồng dữ liệu


14

Chúng tôi nhận được một dòng n1 cặp số khác nhau từ tập {1,,n} .

Làm cách nào tôi có thể xác định số bị thiếu bằng thuật toán đọc luồng một lần và sử dụng bộ nhớ chỉ các bit O(log2n) ?

Câu trả lời:


7

Bạn biết và vìS=n(n+1)i=1ni=n(n+1)2 có thể được mã hóa bằngcác bitO(log(n)),điều này có thể được thực hiện trongbộ nhớO(logn)và trong một đường dẫn (chỉ cần tìmS-currentSum, đây là số bị thiếu).S=n(n+1)2O(log(n))O(logn)ScurrentSum

Nhưng vấn đề này có thể được giải quyết trong trường hợp chung (đối với hằng số ): chúng ta có k số bị thiếu, tìm ra tất cả chúng. Trong trường hợp này thay vì chỉ tính tổng của y i , hãy tính tổng công suất j'st của x i cho tất cả 1 j k (Tôi giả sử x i bị thiếu số và y i là số đầu vào):kkyixi1jkxiyi

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

Hãy nhớ rằng bạn có thể tính đơn giản, vì S 1 = S - y i , S 2 = i 2 - y 2 i , ...S1,...SkS1=SyiS2=i2yi2

Bây giờ để tìm số còn thiếu, bạn nên giải để tìm tất cả x i .(1)xi

Bạn có thể tính toán:

, P 2 = x ix j , ..., P k = x i ( 2 ) .P1=xiP2=xixjPk=xi (2)

Đối với điều này hãy nhớ rằng , P 2 = S 2 1 - S 2P1=S1 , ...P2=S12S22

Nhưng là hệ số củaPi nhưng P có thể là yếu tốduy nhất, vì vậy bạn có thể tìm số còn thiếu.P=(xx1)(xx2)(xxk)P

Đây không phải là suy nghĩ của tôi; đọc này .


1
Tôi không nhận được (2). Có lẽ nếu bạn thêm vào chi tiết của khoản tiền? Liệu bỏ lỡ một Σ ? Pk
Raphael

@Raphael, là bản sắc của Newton, tôi nghĩ rằng nếu bạn có một cái nhìn tại trang wiki tham chiếu của tôi bạn có thể lấy ý tưởng về tính toán, mỗi P i có thể được tính bằng cách trước P s, S j , hãy nhớ công thức đơn giản: 2 x 1x 2 = ( x 1 + x 2 ) 2 - ( xPiPiPSj, bạn có thể áp dụng cách tiếp cận tương tự cho tất cả các quyền hạn. Cũng như tôi đã viếtPi2x1x2=(x1+x2)2(x12+x22)Pilà sigma của một cái gì đó, nhưng không có bất kỳ Σ , vì không chỉ là một Π . PkΣΠ

Là như nó có thể, câu trả lời nên được khép kín ở một mức độ hợp lý. Bạn đưa ra một số công thức, vậy tại sao không làm cho chúng hoàn thành?
Raphael

11

Từ nhận xét trên:

Trước khi xử lý dòng, phân bổ bit, trong đó bạn viết x : = n i = 1 b i n ( i ) ( b i n ( i ) là biểu diễn nhị phân của tôi là pointwise exclusive- hoặc là). Ngây thơ, điều này mất thời gian O ( n ) .log2nx:=i=1nbin(i)bin(i)iO(n)

Khi xử lý luồng, bất cứ khi nào người ta đọc một số , hãy tính x : = x b i n ( j ) . Gọi k là số duy nhất từ { 1 , . . . n } không được bao gồm trong luồng. Sau khi đọc toàn bộ dòng, chúng ta có x = ( n i = 1 b i i n ( i ) ) = b i n ( kjx:=xbin(j)k{1,...n} mang lại kết quả mong muốn.

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

Do đó, chúng tôi đã sử dụng không gian và có thời gian chạy tổng thể là O ( n ) .O(logn)O(n)


3
Tôi có thể đề xuất một tối ưu hóa dễ dàng làm cho thuật toán truyền phát đơn này thực sự: ở bước thời gian , xor x với b i n ( i ) và với đầu vào b i n ( j ) đã đến trên luồng. điều này có thêm lợi ích mà bạn có thể làm cho nó hoạt động ngay cả khi không biết trước n : chỉ cần bắt đầu với một bit được phân bổ cho x và "phát triển" không gian được phân bổ khi cần thiết. ixbin(i)bin(j)nx
Sasho Nikolov

0

valueO(log2n)

fold

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

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
Xin vui lòng gửi mã có thể đọc (giả) chỉ của thuật toán thay vào đó (bỏ qua chính). Ngoài ra, cần bao gồm một bằng chứng / lập luận chính xác ở một số cấp độ.
Raphael

4
@ edA-qamort-ora-y Câu trả lời của bạn cho rằng người đọc biết C ++. Đối với một người không quen thuộc với ngôn ngữ này, không có gì để xem: cả việc tìm đoạn văn có liên quan và hiểu những gì nó đang làm là một thách thức. Mã giả có thể đọc được sẽ làm cho câu trả lời tốt hơn. C ++ không thực sự hữu ích trên trang web khoa học máy tính.
Gilles 'SO- ngừng trở nên xấu xa'

3
Nếu câu trả lời của tôi chứng tỏ không hữu ích, mọi người không cần phải bỏ phiếu cho nó.
edA-qa mort-ora-y

2
+1 để thực sự dành thời gian để viết mã C ++ và kiểm tra nó. Thật không may như những người khác chỉ ra, nó không phải là SO. Vẫn là bạn nỗ lực vào việc này!
Julien Lebot

9
Tôi không hiểu ý của câu trả lời này: bạn lấy giải pháp của người khác, rất đơn giản và rõ ràng rất hiệu quả, và "kiểm tra" nó. Tại sao kiểm tra là cần thiết? Điều này giống như kiểm tra máy tính của bạn thêm số chính xác. Và không có gì không mã hóa abt mã của bạn.
Sasho Nikolov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.