題目描述:在乙個長度為n 的陣列裡的所有數字都在0 到n-1 的範圍內,找出數
組中任意乙個重複的數字.
要求:不能修改原陣列;
空間複雜度為常量o(1);
時間複雜度小於o(n^2);
複雜度時間 o(nlogn) 空間 o(1)
思路實際上,我們可以根據抽屜原理簡化剛才的暴力法。我們不一定要依次選擇數,然後看是否有這個數的重複數,我們可以用二分法先選取n/2,按照抽屜原理,整個陣列中如果小於等於n/2的數的數量大於n/2,說明1到n/2這個區間是肯定有重複數字的。比如6個抽屜,如果有7個襪子要放到抽屜裡,那肯定有乙個抽屜至少兩個襪子。這裡抽屜就是1到n/2的每乙個數,而襪子就是整個陣列中小於等於n/2的那些數。這樣我們就能知道下次選擇的數的範圍,如果1到n/2區間內肯定有重複數字,則下次在1到n/2範圍內找,否則在n/2到n範圍內找。下次找的時候,還是找一半。
注意我們比較的mid而不是nums[mid]
因為mid是下標,所以判斷式應為cnt > mid,最後返回min
**實現:
public class solution
}// 如果小於等於中間數的數量大於中間數,說明前半部分必有重複
if(cnt > mid) else
}return min;
}}
複雜度
時間 o(n) 空間 o(1)
思路假設陣列中沒有重複,那我們可以做到這麼一點,就是將陣列的下標和1到n每乙個數一對一的對映起來。比如陣列是213,則對映關係為0->2, 1->1, 2->3。假設這個一對一對映關係是乙個函式f(n),其中n是下標,f(n)是對映到的數。如果我們從下標為0出發,根據這個函式計算出乙個值,以這個值為新的下標,再用這個函式計算,以此類推,直到下標超界。實際上可以產生乙個類似鍊錶一樣的序列。比如在這個例子中有兩個下標的序列,0->2->3。
但如果有重複的話,這中間就會產生多對一的對映,比如陣列2131,則對映關係為0->2, ->1, 2->3。這樣,我們推演的序列就一定會有環路了,這裡下標的序列是0->2->3->1->1->1->1->…,而環的起點就是重複的數。
所以該題實際上就是找環路起點的題,和linked list cycle ii一樣。我們先用快慢兩個下標都從0開始,快下標每輪對映兩次,慢下標每輪對映一次,直到兩個下標再次相同。這時候保持慢下標位置不變,再用乙個新的下標從0開始,這兩個下標都繼續每輪對映一次,當這兩個下標相遇時,就是環的起點,也就是重複的數。對這個找環起點演算法不懂的,請參考floyd』s algorithm。
注意第一次找快慢指標相遇用do-while迴圈
**實現:
public class solution while(slow != fast);
int find = 0;
// 用乙個新指標從頭開始,直到和慢指標相遇
while(find != slow)
return find;
}}
找出陣列重複的數
1 在乙個長度為 n 的陣列裡的所有數字都在 0 n 1 的範圍內,找出任意乙個重複的數。簡明思路 按照題目要求,如果這個陣列裡面的數恰好沒有重複的數,則陣列下標跟對應的值相等。否則,當掃瞄到下標為 i 的數字時,比較這個下標的值 m 是不是等於 i 如果是,說明這個值就在它對應的下標下,繼續掃瞄 ...
找出陣列中所有重複的數
include stdafx.h for i 0 to n 1 while a a i a i swap a i a a i end while end for for i 0 to n 1 if a i i then print a i end if end for void swap int a...
287 找出陣列中重複的數
交換法主要思想是通過交換陣列元素,使得陣列上的元素在正確的位置上。遍歷陣列,如果第 i 位上的元素不是 i 1,那麼一直交換第 i 位和 nums i 1 位置上的元素。public static list test1 int nums list list newlist for int i 0 i...