1. 程式人生 > >[LeetCode]1.TwoSum(Python實現)

[LeetCode]1.TwoSum(Python實現)

1.題目描述

給定一個整數陣列和一個目標值,找出陣列中和為目標值的兩個數。
你可以假設每個輸入只對應一種答案,且同樣的元素不能被重複利用
  • 示例:
    給定 nums = [2, 7, 11, 15], target = 9
    因為 nums[0] + nums[1] = 2 + 7 = 9
    所以返回 [0, 1]

2.程式碼實現

1. 方法一:

[分析]:
       自然而然的想法,首先用for迴圈對nums陣列進行遍歷,從第一個元素開始,然後再查詢陣列中有沒有target-nums[i]這個元素;有的話,則返回當前元素下標與另一個元素的下標,作為結果輸出。程式碼如下:

class
Solution(object):
def twoSum(self, nums, target)for i in range(len(nums)): if (target - nums[i]) in nums: return [i,nums.index(target - nums[i])]

        然而,實際程式設計過程中出現了這麼一個問題,Python提供的list.index(value,from,to) “左閉右開區間”,在不指定from,to的時候,該方法預設返回陣列中第一次出現該value的index值

,在case([3,4,2],6)中,應該輸出[1,2],而按照前面的思路,直接輸出了[0,0],這顯然是不正確的,於是直接的想法是比較兩個元素對應的index是否相等,是的話,就pass掉,程式碼改為如下:

class Solution(object):
    def twoSum(self, nums, target)for i in range(len(nums)):
                if (target - nums[i]) in nums:
                    idx = nums.index(target - nums[i])
                    if
i == idx: pass else: return [i,idx]

       然而,還是出了問題,比如說在case([0,3,4,0],0)中,應該輸出[0,3],但上面方法卻輸出了null,我的一個新思路是,是不是應該在查詢 target - nums[i] 元素的index時,設定一個from值,應該從當前元素的後面一個開始查詢元素,於是程式碼改為如下:

class Solution(object):
    def twoSum(self, nums, target):
        for i in range(len(nums)):
                if (target - nums[i]) in nums:
                    idx = nums.index(target - nums[i],i+1) # 這裡設定了from
                    return [i,idx]

       如此一來,貌似解決了case([0,3,4,0],0)的問題,結果執行的時候,case([3,4,2],6)發生執行錯誤,程式在執行第一個元素的時候,查詢到nums裡有(6-3),但是在搜index的時候,由於設定了搜尋範圍,查詢不到元素3的索引,可謂是顧此失彼。
       沒辦法,只能繼續思考,如何解決這個兩難的問題,突然一個想法產生,我何不對nums陣列進行切片呢?即我在判斷陣列中是否包含 target - nums[i] 元素時,不應該對整個陣列進行查詢,而是應該對num[i+1:]進行查詢,程式碼如下:

class Solution(object):
    def twoSum(self, nums, target):
        for i in range(len(nums)):
            num = target - nums[i]
            if num in nums[i+1:]:
                return [i, nums.index(num,i+1)]

       最終程式測試結果:

       執行用時804ms,戰勝64.84%的python提交記錄,這說明我的演算法還有很大的提升空間,時間複雜度為O(n^2),for迴圈的複雜度為O(n), x in list方法的複雜度為O(n),取切片的複雜度為O(k),index的方法為O(n),這裡複雜度的計算參考了官網
       這裡我偷懶了,直接在網上找了別人的優秀演算法,看完之後,驚為天人,在方法二中來進行說明。

2.方法二:
       先看程式碼:

class Solution(object):
    def twoSum(self, nums, target):
        nums_dict = {}
        for i, num in enumerate(nums):
            if num in nums_dict:
                return [nums_dict[num], i]
            else:
                nums_dict[target - num] = i

       程式碼思路:這個演算法的核心思想是構造一個字典,字典用來儲存當前元素完成target需要的元素值作為key,當前元素的index作為value。然後遍歷過程中進行判斷,當前元素是不是屬於我想要的元素,是的話,直接輸出 [字典中該元素的下標,當前遍歷元素下標]
       思考:這個演算法快在哪裡?
       從時間複雜度的角度來看,第一層for迴圈是O(n),字典採用的是hash函式的結構,所以在 x in dict的查詢過程中,時間複雜度為O(1),而這裡沒用到index查詢,而是直接獲取value值,而字典的Get Item的複雜度也是O(1),所以整個演算法的時間複雜度為O(n),不過這裡的空間複雜度是O(n),用空間換時間。
       最終程式測試結果: