原題如下
給定一個整數數組和一個目標值,找出數組中和爲目標值的兩個數。
你可以假設每個輸入只對應一種答案,且同樣的元素不能被重複利用。
示例:
給定 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) 但是比上面的算法代碼上更加簡潔, 且節約了構建索引的部分循環次數