簡體   English   中英

O(n)算法找到從1到n(非奇數)的連續整數數組中的奇數輸出

[英]O(n) algorithm to find the odd-number-out in array of consecutive integers from 1 to n(not odd numbers)

我試圖解決這個問題時遇到了很多麻煩,而麻煩的根源在於創建了一個O(n)復雜度的算法。 這是我正在努力解決的問題:

長度為n的數組A包含范圍為[0, .., n - 1]整數。 但是,它只包含n - 1不同的數字。 因此,其中一個數字丟失,另一個數字重復。 編寫一個Java方法,將A作為輸入參數並返回缺少的數字; 該方法應該在O(n)運行。

例如,當A = [0, 2, 1, 2, 4] oddOneOut() A = [0, 2, 1, 2, 4]oddOneOut()應返回3 ; A = [3, 0, 0, 4, 2, 1] oddOneOut() A = [3, 0, 0, 4, 2, 1]oddOneOut()應返回5

顯然,這是一個用O(n 2 )算法解決的簡單問題,(很可能是O(n) ,我只是沒有看到它!)。 我試圖用各種方法解決它,但無濟於事。 我試圖用Java解決它,但是如果你更習慣解決它,那也沒關系。

先感謝您...

假設缺少的數字是x ,副本是y 如果您添加所有數字,總和將是:

(n - 1) * n / 2 - x + y

從上面,你可以找到(x - y) .....(1)

同樣,將數字的平方相加。 總和將是:

(n - 1) * n * (2 * n - 1) / 6 - x 2 + y 2

從上面你得到(x 2 - y 2 ) ....(2)

(2) / (1) gives (x + y).....(3)

(1)+(3)給出2 * x ,從而可以找到xy

注意,在該解決方案中存在O(1)額外存儲並且是O(n)時間復雜度 上面的其他解決方案是不必要的O(n)額外存儲。

混合C / C ++中的代碼更清晰:

#include <stdio.h>

int findDup(int *arr, int n, int& dup, int& missing)
{
    int sum = 0;
    int squares = 0;

    for (int i = 0; i < n; i++) {
        sum += arr[i];
        squares += arr[i] * arr[i];
    }

    sum = (n - 1) * n / 2 - sum; // x - y

    squares = (n - 1) * n * (2 * (n - 1) + 1) / 6 - squares; // x^2 - y^2

    if (sum == 0) {
        // no duplicates
        missing = dup = 0;
        return -1;
    }
    missing = (squares / sum + sum) / 2; // ((x^2 - y^2) / (x - y) + (x - y)) / 2 = ((x + y) + (x - y)) / 2 = x

    dup = missing - sum; // x - (x - y) = y

    return 0;
}


int main(int argc, char *argv[])
{
    int dup = 0;
    int missing = 0;

    int a[] = {0, 2, 1, 2, 4};

    findDup(a, sizeof(a) / sizeof(int), dup, missing);
    printf("dup = [%d], missing = [%d]\n", dup, missing);

    int b[] = {3, 0, 0, 4, 2, 1};
    findDup(b, sizeof(b) / sizeof(int), dup, missing);
    printf("dup = [%d], missing = [%d]\n", dup, missing);

    return 0;
}

輸出:

dup = [2], missing = [3]
dup = [0], missing = [5]

一些python代碼:

def finddup(lst):
    sum = 0
    sumsq = 0
    missing = 0
    dup = 0
    for item in lst:
        sum = sum + item
        sumsq = sumsq + item * item
    n = len(a)
    sum = (n - 1) * n / 2 - sum
    sumsq = (n - 1) * n * (2 * (n - 1) + 1) / 6 - sumsq
    if sum == 0:
        return [-1, missing, dup]
    missing = ((sumsq / sum) + sum) / 2
    dup = missing - sum
    return [0, missing, dup]

found, missing, dup = finddup([0, 2, 1, 2, 4])
if found != -1:
    print "dup = " + str(dup) + " missing = " + str(missing)

print finddup([3, 0, 0, 4, 2, 1])

輸出:

dup = 2 missing = 3
[-1, 0, 0]

迭代數組兩次:那仍然是O(n)。 創建一個臨時的布爾數組(或一個Java BitSet)來保存你得到的數字。 第二次執行循環時,檢查布爾數組中是否有孔。

使用哈希集並單次傳遞以檢測哪個數字是重復的。 在同一次迭代期間,跟蹤所有數字的累積總和。

現在計算所有數字不同的預期總數: n * (n - 1) / 2 減去你找到的總數。 您將留下“缺失”數字減去副本。 添加副本以獲得答案。

由於哈希表訪問是恆定時間,並且我們使用單次傳遞,因此這是O(n) (請注意,單次傳遞不是絕對必要的:Martijn指出固定數量的傳遞仍然是線性復雜度是正確的。)

這可能是有意義的,雖然我不確定它在什么條件下(如果有的話)表現最好。 我們的想法是,我們將把每個元素移動到數組中的正確位置( 0到索引0等),直到它變得清楚什么是缺失的和什么是額外的。

def findmissing(data):
    upto = 0
    gap = -1
    while upto < len(data):
        #print data, gap
        if data[upto] == upto:
            upto += 1
            continue
        idx = data[upto]
        if idx is None:
            upto += 1
            continue
        data[upto], data[idx] = data[idx], data[upto]
        if data[upto] == data[idx]:
            print 'found dupe, it is', data[upto]
            data[upto] = None
            gap = upto
            upto += 1
        elif data[upto] is None:
            gap = upto
    return gap

if __name__ == '__main__':
    data = range(1000)
    import random
    missing = random.choice(data)
    print missing
    data[missing] = data[0]
    data[0] = random.choice(data[1:])
    random.shuffle(data)
    print 'gap is', findmissing(data)

這是為O(n),因為每一步無論是增量upto 數組中移動的價值為它的“正確”的地方,每個這樣的事情只能發生n倍。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM