Two Sum系列問題在 LeetCode 上有好幾道,這篇文章就挑出有代表性的兩道,介紹一下這種問題怎么解決。
TwoSum I
這個問題的最基本形式是這樣:給你一個數組和一個整數target,可以保證數組中存在兩個數的和為target,請你返回這兩個數的索引。
比如輸入nums = [3,1,3,6],target = 6,算法應該返回數組[0,2],因為 3 + 3 = 6。
這個問題如何解決呢?首先最簡單粗暴的辦法當然是窮舉了:
這個解法非常直接,時間復雜度 O(N^2),空間復雜度 O(1)。
更好一點的解法,可以通過一個哈希表減少時間復雜度:
這樣,由于哈希表的查詢時間為 O(1),算法的時間復雜度降低到 O(N),但是需要 O(N) 的空間復雜度來存儲哈希表。不過綜合來看,是要比暴力解法高效的。
我覺得 Two Sum 系列問題就是想教我們如何使用哈希表處理問題。我們接著往后看。
TwoSum II
稍微修改一下上面的問題,要求我們設計一個類,擁有兩個 API:
classTwoSum{ //向數據結構中添加一個數number publicvoidadd(intnumber); //尋找當前數據結構中是否存在兩個數的和為value publicbooleanfind(intvalue); }
如何實現這兩個 API 呢,我們可以仿照上一道題目,使用一個哈希表輔助find方法:
進行find的時候有兩種情況,舉個例子:
情況一:如果連續 add 了[3,2,3,5],那么freq是{3:2,2:1,5:1},執行find(6),由于 3 出現了兩次,3 + 3 = 6,所以返回 true。
情況二:freq是{3:2,2:1,5:1},執行find(7),那么key為 2,other為 5 時算法可以返回 true。
除了上述兩種情況外,find只能返回 false 了。
對于這個解法的時間復雜度呢,add方法是 O(1),find方法是 O(N),空間復雜度為 O(N),和上一道題目比較類似。
但是對于 API 的設計,是需要考慮現實情況的。比如說,我們設計的這個類,使用find方法非常頻繁,那么每次都要 O(N) 的時間,豈不是很浪費費時間嗎?對于這種情況,我們是否可以做些優化呢?
是的,對于頻繁使用find方法的場景,我們可以進行優化。我們可以參考上一道題目的暴力解法,借助哈希集合來針對性優化find方法:
這樣sum中就儲存了所有加入數字可能組成的和,每次find只要花費 O(1) 的時間在集合中判斷一下是否存在就行了,顯然非常適合頻繁使用find的場景。
三、總結
對于 TwoSum 問題,一個難點就是給的數組無序。對于一個無序的數組,我們似乎什么技巧也沒有,只能暴力窮舉所有可能。
一般情況下,我們會首先把數組排序再考慮雙指針技巧。TwoSum 啟發我們,HashMap 或者 HashSet 也可以幫助我們處理無序數組相關的簡單問題。
另外,設計的核心在于權衡,利用不同的數據結構,可以得到一些針對性的加強。
最后,如果 TwoSum I 中給的數組是有序的,應該如何編寫算法呢?答案很簡單,前文雙指針技巧匯總寫過:
int[]twoSum(int[]nums,inttarget){ intleft=0,right=nums.length-1; while(lefttarget){ right--;//讓sum小一點 } } //不存在這樣兩個數 returnnewint[]{-1,-1}; }
-
存儲
+關注
關注
13文章
4266瀏覽量
85688 -
數組
+關注
關注
1文章
416瀏覽量
25915
原文標題:Two Sum 問題的核心思想
文章出處:【微信號:TheAlgorithm,微信公眾號:算法與數據結構】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論