來刷 LeetCode 啊

Python之禪發表於2018-11-28

為什麼要刷LeetCode,刷LeetCode吃力正常嗎?看完大神們怎麼說,是不是有必要給自己一個小目標,比如刷滿1000題

~

給定一個整數陣列 nums 和一個目標值 target,請你在該陣列中找出和為目標值的 兩個 整數。你可以假設每種輸入只會對應一個答案。但是,你不能重複利用這個陣列中同樣的元素。

示例:

給定 nums = [2, 7, 11, 15], target = 9
因為 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

題目難度:easy

做這道題之前,我們先複習一下幾個資料結構的特性

列表的查詢複雜度是 O(n),集合的查詢複雜度是 O(1),字典的查詢複雜度也是 O(1)。關於這三種資料結構的各種操作的時間複雜度可參考連結: https://wiki.python.org/moin/TimeComplexity , 這裡是中譯版本 http://www.orangecube.net/python-time-complexity

看到這道題,你可能一眼就能想到的解決辦法就是暴力破解法。大概思路就是 n*n 輪遍歷,第1個n輪是首先取出第一個元素 n ,然後從剩下的元素中遍歷,找到某個等於 target-n 的值,如果沒找到,就開始第2個n輪遍歷,取出第二個元素,直到找到目標元素為止。

def two_sum(nums, target):
   for i, n in enumerate(nums):
       if target - n in nums[i + 1:]:
           return n, target - n

nums = [2, 7, 11, 15]
target = 9
print(two_sum(nums, target))

>>>(2, 7)

使用 in 關鍵字在列表中查詢元素的時間複雜度是O(n),外層for迴圈的複雜度也是O(n),所以這種演算法的時間複雜度是 O(n^2)

然後我發現另外一個缺點,在 Python 中,沒法基於原陣列進行遍歷,外迴圈每次迭代的時候,要建立一個新的列表nums[i + 1:],這樣就造成了這個演算法的空間複雜度變成了 O(n),如果換成C或者Java就不會有這個問題,這也是 Python 慢的一種原因吧。

方法二

既然列表查詢的複雜度是 O(n),而 集合和字典的查詢複雜度是常量 O(1),所以我們可以考慮先將列表轉換成字典或者集合。

def two_sum(nums, target):
   s= set(nums)
   for n in nums:
       m = target - n
       if m in s and n != m:
           return n, m

nums = [2, 7, 11, 15]
target = 9
print(two_sum(nums, target))

最終這個演算法的複雜度就變成了 O(n),空間複雜度也是 O(n),所以這種演算法要優於第一種的。如果將列表轉換為字典,可以將列表元素作為字典的key,而元素的索引位置作為字典的value,這樣就可以知道這兩個目標元素的位置是哪裡,這是用集合沒法做到的。

總結

學演算法首先要把基本的資料結構搞懂,例如列表、集合、字典、佇列、連結串列、樹、二叉樹、圖等等,理解各種資料結構操作的特性,然後你做起題目來就遊刃有餘了。


推薦閱讀

640?
優秀如你
用轉發點贊支援我

相關文章