Leet Code 015 Three Sum

給定一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。
注意:答案中不可以包含重複的三元組。

例如, 給定數組 nums = [-1, 0, 1, 2, -1, -4],

滿足要求的三元組集合爲:
[
[-1, 0, 1],
[-1, -1, 2]
]

面試中 優先考慮雙指針,並使用set保存res,即可以不考慮去重

思路一:利用twoSum
遍歷nums,然後轉換爲twoSum問題,但是要排除重複結果,判重操作時間O(n),twoSum本身時間O(n),空間O(n),總體時間複雜度O(n^3),空間複雜度O(n)

class Solution(object):  # 此法也超時
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        def twoSum(nums, target):
            lookup = {}
            for num in nums:
                if target - num in lookup:
                    if (-target ,target - num, num) not in res:
                        res.append((-target ,target - num, num))
                lookup[num] = target - num

        n = len(nums)
        nums.sort()
        res = []
        for i in range(n):
            twoSum(nums[i+1:], 0-nums[i])
        return [list(i) for i in res]

思路二:暴力法
先給nums排序,滿足結果從小到大排列,三層循環

class Solution(object):
    def threeSum(self, nums):
        n = len(nums)
        res = []
        nums.sort()
        for i in range(n):
            for j in range(i,n):
                for k in range(j,n):
                    if nums[i] + nums[j] + nums[k] == 0 and j != i and k != j and k != i: 
                        curRes = [nums[i],nums[j],nums[k]]
                        if curRes not in res:
                            res.append(curRes)
    
        return res

思路三:優化二
兩個for loop枚舉a,c,則b=-a-c,然後去dyct中查詢-a-c是否存在。利用set保存res,達到去重效果。
整體時間複雜度O(n^2),空間複雜度O(n)

def threeSum(nums):
    if len(nums) < 3:
        return []
    nums.sort()
    res = set()
    for i,a in enumerate(nums[:-2]):
        if i >= 1 and a == nums[i-1]:
#             兩個連續的值相等時,已經處理過了,跳過此次循環,
            continue
        if v > 0: break  ##因爲已經排序了,所以到大於零的位置,之後的數字都是大於零的,肯定沒有符合條件的組合了

        dyct = {}
        for c in nums[i+1:]:
            if c not in dyct:
                dyct[-a-c] = None
            else:
                res.add((a, -a-c, c))
    return list(map(list, res))
threeSum([-1, 0, 1, 2, -1, -4])
[[-1, -1, 2], [-1, 0, 1]]

思路四:雙指針
排序好nums,遍歷nums,對nums[i+1:],使用兩個指針l,r分別從左右開始,計算當前數nums[i]和nums[l],nums[r]之和s,若s小於0,由於nums是排好序的,只需l右移,若s大於0則只需r左移,若等於0,則將nums[i],nums[l],nums[r]存入res列表,並左移r 右移l 繼續比較。直至兩個指針發生碰撞。
注意點:對於相鄰重複的元素,需要跳過。
由於需要遍歷nums,且雙指針遍歷nums[i+1:],則總體時間複雜度爲O(n^2),空間複雜度爲O(n)

def threeSum(nums):
    '''
    使用set保存res,不需要考慮判重,簡單直接,思路清晰
    '''
    res = set()
    nums.sort()
    for i in range(len(nums)-2):
        l,r = i+1,len(nums)-1
        while l < r:
            s= nums[i] + nums[l] + nums[r]
            if s < 0:
                l += 1
            elif s >0:
                r -= 1
            else:
                res.add((nums[i],nums[l],nums[r]))
                l += 1
                r -= 1
    return [list(i) for i in res]
threeSum([-1, 0, 1, 2, -1, -4])
[[-1, -1, 2], [-1, 0, 1]]
threeSum([0,0,0,0,0,0,0,0,0])
[[0, 0, 0]]

充分考慮nums結構,進行判重,減少操作,減少時間,加大代碼複雜度
且利用排序好的nums,可知當nums[i]>0時,i,i+1,i+2三個元素都大於零,即i以後的元素不存在解。

def threeSum(nums):
    '''
    使用list保存res,在過程中判重。
    '''
    res = []
    nums.sort()
    for i in range(len(nums)-2):
        if i>0 and nums[i] == nums[i-1]: # 兩個連續的值相等時,已經處理過了,跳過此次循環,
            continue
        if nums[i]>0: break #因爲已經排序了,所以到大於零的位置,之後的數字都是大於零的,肯定沒有符合條件的組合了
        l,r = i+1,len(nums)-1
        while l < r:
            s= nums[i] + nums[l] + nums[r]
            if s < 0:
                l += 1
            elif s >0:
                r -= 1
            else:
                res.append((nums[i],nums[l],nums[r]))
                while l < r and nums[l] == nums[l+1]: # 再去重
                    l += 1
                while l < r and nums[r] == nums[r-1]:
                    r -= 1
                l += 1
                r -= 1
    return res
threeSum([-1, 0, 1, 2, -1, -4])
[(-1, -1, 2), (-1, 0, 1)]

執行用時 : 844 ms, 在3Sum的Python3提交中擊敗了88.77% 的用戶
內存消耗 : 16.4 MB, 在3Sum的Python3提交中擊敗了97.63% 的用戶

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