leetCode 1號題詳解, 兩數之和的key , python3三種方法實現
阿新 • • 發佈:2018-11-09
原題如下
給定一個整數陣列和一個目標值,找出陣列中和為目標值的兩個數。
你可以假設每個輸入只對應一種答案,且同樣的元素不能被重複利用。
示例:
給定 nums = [2, 7, 11, 15], target = 9
因為 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
第一種解法:暴力方式 複雜度是O(n^2)
class Solution: def twoSum(self, nums, target): """ :type nums: List[int] :type target: int :rtype: List[int] """ for i in range(len(nums)): for j in range(len(nums) - i): if nums[i] + nums[j] == target: #因為題目說明一個解, 這裡直接返回 return [i, j] if __name__ == "__main__": a = Solution() print(a.twoSum([8,2,5,2,5,11], 10))
這裡思考的是, 因為我們是要對比一個數組中的兩個數之間的合的關係, 兩次遍歷同一個陣列複雜度可以通過字典建立索引來解決其中的一次遍歷問題
見程式碼: 複雜度就是O(n) + O(1)*O(N) == 2O(n) = O(N)
class Solution: def twoSum(self, nums, target): """ :type nums: List[int] :type target: int :rtype: List[int] """ dictNums = {} for i in range(len(nums)): #這裡迴圈同一個陣列,創造字典,以便第二次迴圈對比的時候,能夠O(1)級別的查詢 dictNums[nums[i]] = i for i in range(len(nums)): if dictNums.get(target-nums[i], 0) != 0 and i != dictNums[target-nums[i]]: #因為題目說條件是假設一個解,所以直接返回 return [i, dictNums[target-nums[i]]] return False if __name__ == "__main__": a = Solution() print(a.twoSum([8,2,5,2,5,11], 10))
第二種方法就從O(n^2)降到了O(n) , 但是發現上面第二種方式是否可以再優化一下呢? 可否把兩次迴圈放在一次迴圈裡面呢?
答案是肯定的, 看下面的陣列假如我們要找和為10的兩個數, 如果迴圈到了第三個數, 其實對於那麼只需要前三個數建立的字典與後面的數進行匹配, 也就是說一次把陣列倒置建立索引形成字典是存在一些浪費的, 因為有可能提前找到答案
1 | 2 | 5 | 2 | 9 | 6 | 3 |
那麼在一次改進, 第三種方法:
class Solution: def twoSum(self, nums, target): """ :type nums: List[int] :type target: int :rtype: List[int] """ dictNums = {} for i in range(len(nums)): if target-nums[i] in dictNums: #因為題目說條件是假設一個解,所以直接返回 return [dictNums[target-nums[i]], i] else: dictNums[nums[i]] = i return False if __name__ == "__main__": a = Solution() print(a.twoSum([8,2,5,2,5,11], 10))
雖然複雜度還是同樣的O(n) 但是比上面的演算法程式碼上更加簡潔, 且節約了構建索引的部分迴圈次數