【LeetCode】1、兩數之和

【LeetCode】1、兩數之和

【題目】

給定一個整數數組和一個目標值,找出數組中和爲目標值的兩個數。

你可以假設每個輸入只對應一種答案,且同樣的元素不能被重複利用。

示例:

給定 nums = [2, 7, 11, 15], target = 9

因爲 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

目錄

java解法

解法一、暴力法

暴力法很簡單。遍歷每個元素x ,並查找是否存在一個值與 targetx 相等的目標元素。

public int[] twoSum(int[] nums, int target) {
    for (int i = 0; i < nums.length; i++) {
        for (int j = i + 1; j < nums.length; j++) {
            if (nums[j] == target - nums[i]) {
                return new int[] { i, j };
            }
        }
    }
    throw new IllegalArgumentException("No two sum solution");
}

複雜度分析

  • 時間複雜度:O(n2) , 對於每個元素,我們試圖通過遍歷數組的其餘部分來尋找它所對應的目標元素,這將耗費O(n) 的時間。因此時間複雜度爲O(n2)
  • 空間複雜度:O(1)

解法二、兩遍哈希表

爲了對運行時間複雜度進行優化,我們需要一種更有效的方法來檢查數組中是否存在目標元素。如果存在,我們需要找出它的索引。保持數組中的每個元素與其索引相互對應的最好方法是什麼?哈希表。

通過以空間換取速度的方式,我們可以將查找時間從 O(n) 降低到O(1) 。哈希表正是爲此目的而構建的,它支持以 近似 恆定的時間進行快速查找。我用“近似”來描述,是因爲一旦出現衝突,查找用時可能會退化到 O(n) 。但只要你仔細地挑選哈希函數,在哈希表中進行查找的用時應當被攤銷爲 O(1)

一個簡單的實現使用了兩次迭代。在第一次迭代中,我們將每個元素的值和它的索引添加到表中。然後,在第二次迭代中,我們將檢查每個元素所對應的目標元素targetnums[i] 是否存在於表中。注意,該目標元素不能是nums[i] 本身!

public int[] twoSum(int[] nums, int target) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        map.put(nums[i], i);
    }
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        if (map.containsKey(complement) 
              && map.get(complement) != i) {
            return new int[] { i, map.get(complement) };
        }
    }
    throw new IllegalArgumentException("No two sum solution");
}

複雜度分析

  • 時間複雜度: O(n) , 我們把包含有 n 個元素的列表遍歷兩次。由於哈希表將查找時間縮短到 O(1) ,所以時間複雜度爲 O(n)
  • 空間複雜度: O(n) , 所需的額外空間取決於哈希表中存儲的元素數量,該表中存儲了 n 個元素。

解法三、一遍哈希表

事實證明,我們可以一次完成。在進行迭代並將元素插入到表中的同時,我們還會回過頭來檢查表中是否已經存在當前元素所對應的目標元素。如果它存在,那我們已經找到了對應解,並立即將其返回。

public int[] twoSum(int[] nums, int target) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        if (map.containsKey(complement)
               && map.get(complement) != i) {
            return new int[] { map.get(complement), i };
        }
        map.put(nums[i], i);
    }
    throw new IllegalArgumentException("No two sum solution");
}

複雜度分析

  • 時間複雜度: O(n) , 我們只遍歷了包含有 n 個元素的列表一次。在表中進行的每次查找只花費 O(1) 的時間。
  • 空間複雜度: O(n) , 所需的額外空間取決於哈希表中存儲的元素數量,該表最多需要存儲 n 個元素。

python解法

解法一

    def twoSum(self, nums, target):
        nums_bak = nums.copy()
        nums.sort()
        i = 0
        j = 0
        for k in range(0, (len(nums) - 1)):
            if nums[k] + nums[k + 1] >= target:
                i = k
                j = k + 1
                break
        while i >= 0 and j < len(nums):
            if nums[i] + nums[j] < target:
                j += 1
            elif nums[i] + nums[j] > target:
                i -= 1
            else:
                if nums[i] == nums[j]:
                    return [nums_bak.index(nums[i]), nums_bak.index(nums[j], i + 1)]
                else:
                    return [nums_bak.index(nums[i]), nums_bak.index(nums[j])]

解法二

def twoSum(self, nums, target):
        numsMap = {}
        i = 0
        while(i<len(nums)):
            num = nums[i]
            component = target - num
            if component in numsMap and numsMap.get(component) != i :
                return [numsMap.get(component),i]
            else :
                numsMap[num] = i
            i = i+1    

解法三

def twoSum(self, nums, target):
        dic = {}
        for i, num in enumerate(nums):
            if (target - num) in dic:
                return i,dic[target - num]
            dic[num] = i

解法四

 def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        i = 0
        j = 0
        dic = {}
        for i in range(len(nums)):
            if nums[i] in dic:
                j = dic[nums[i]]
                return [i, j]
                break
            dic[target-nums[i]] = i

歡迎大家一起交流討論

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章