287. 尋找重複數
不能更改原陣列(假設陣列是唯讀的)。
只能使用額外的 o(1) 的空間。
時間複雜度小於 o(n2) 。
陣列中只有乙個重複的數字,但它可能不止重複出現一次。
因為不能能改原來的陣列,並且只能使用額外o1的空間,所以我們不能使用map記錄,也不能維護乙個新的陣列
因為時間複雜度要在n2以內,所以暴力查詢也是不可取的
因為資料範圍在1~n-1,所以可以保證不會陣列越界,因此使用鍊錶中快慢指標尋找環演算法
1、當fast指標僅僅只比slow指標多走乙個環,如圖所示
2、第一次相遇的時候,如圖
3、這個時候將fast 重新賦值為開頭,如圖
4、再走兩次,則找到了環的入口結點
重新梳理一下步驟,解題思路
a、第一步,找環中相匯點。分別用fast,slow指向鍊錶頭部,slow每次走一步,fast每次走二步,直到fast==slow找到在環中的相匯點。
b、第二步,找環的入口。接上步,當fast==slow時,fast所經過節點數為2x,slow所經過節點數為x,設環中有n個節點,fast比slow多走一圈有2x=n+x; n=x;
可以看出slow實際走了乙個環的步數,再讓fast指向鍊錶頭部,slow位置不變。
假設鍊錶開頭到環介面的距離是y,如下圖所示,那麼x-y表示slow指標走過的除鍊錶開頭y在環中走過的距離,那麼slow再走y步,此時fast結點與slow結點相遇,fast == slow ,x-y+y=x = n,即此時slow指向環的入口。
442. 陣列中重複的資料
比較好的解法是鴿巢原理+亦或交換資料
不用到任何額外空間並在o(n)時間複雜度
把大小為i的數字,放進下標為i-1的位置上,排完之後還剩下的位置不對的,就是多餘的。
對第i位置上的數字k,因為k!=i-1,所以要把k丟到k-1的位置上,然後再看看換過來的數字是不是i-1,不是就繼續換(有點像排序演算法),當這個位置正確後,就進入下乙個位置。
當所有位置處理完以後,再掃一遍,發現位置和數字不匹配的數字就是多餘的數字,因為不能採用額外空間,所以使用無額外記憶體的亦或交換(加減交換也可以)。
public listfindduplicates(int nums)public void swap(int nums,int a,int b)
鴿巢原理小結
最基礎的原理便是n 1的物體放到n個盒子裡,至少有乙個盒子放了兩個物體。poj 2356 有n個數,從中選出幾個數的和是n的倍數。不得不說數學是個神奇的東西,結論是任意的n個數,必然能找到連續的m個數之和是n的倍數。接下來簡單證明一下,組合數學書中,黑書都有介紹。sk表示a1 a2 ak,如果sk是...
11 抽屜原理 鴿巢原理
桌上有十個蘋果,要把這十個蘋果放到九個抽屜裡,無論怎樣放,我們會發現至少會有乙個抽屜裡面至少放兩個蘋果。這一現象就是我們所說的 抽屜原理 抽屜原理的一般含義為 如果每個抽屜代表乙個集合,每乙個蘋果就可以代表乙個元素,假如有n 1個元素放到n個集合中去,其中必定有乙個集合裡至少有兩個元素。抽屜原理有時...
鴿巢原理簡單應用
從n個數裡面取出一些數,這些數的和是n的倍數。並輸出這些數。先預處理出前n個數的和用sum i 表示前i個數的和。若某個sum i 是n的倍數,直接輸出前i個數即可。否則說明n個數中對n取餘的結果有n 1種,即餘數為 1 n 1 根據鴿巢原理知必定至少存在兩個sum i 與sum j 對n取餘的結果...