[英]Given an array of +ve integers, Find the number which occurs odd number of times in O(n) time & constant space.
[英]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
,從而可以找到x
和y
。
注意,在該解決方案中存在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.