1. 程式人生 > >LeetCode Notes_#18 4Sum

LeetCode Notes_#18 4Sum

LeetCode Notes_#18 4Sum

LeetCode 

Contents

題目

Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:

The solution set must not contain duplicate quadruplets.

Example:

Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.

A solution set is:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

思路和解答

思路

問題的內容跟之前的2sum,3sum都是很相似的,僅僅是修改了元素的個數,增加了複雜度(不可以再使用暴力迴圈的方式,而是要用盡可能少的指標,儘可能少的list訪問次數去達成目標)

  • 2sum,兩個指標兩層迴圈,遍歷所有可能的兩兩組合形式
  • 3sum,3sumcloest,三個指標,第一個指標遍歷所有元素,後面兩個指標從左右向中間移動,這並沒有遍歷到所有情況,但是不會漏掉需要的情況(前提是提前對list排序,然後根據結果的大小動態移動左右指標)
  • 4sum是怎樣呢?一定還是需要四個指標的,主要問題在於如何去優化指標遍歷元素的方式。

解答

#第一版,通過了最簡單的case,但是沒有考慮到nums裡邊數字出現重複的情況
class Solution(object):
    def
fourSum(self, nums, target):
""" :type nums: List[int] :type target: int :rtype: List[List[int]] """ res=[] nums.sort() for i in range(len(nums)-3): for j in range(i+1,len(nums)-2): l=j+1 r=len(nums)-1 while(l<r): sum=nums[i]+nums[j]+nums[l]+nums[r] if sum<target: l+=1 if sum>target: r-=1 if sum==target: res.append([nums[i],nums[j],nums[l],nums[r]]) l+=1 r-=1 return res
#第二版,目的是去除重複,在pycharm上面執行結果沒毛病,但是不知道為什麼一樣的程式碼在leetcode上面執行結果不一樣...
class Solution(object):
    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        res=[]
        nums.sort()
        for i in range(len(nums)-3):
            if i>0 and nums[i]==nums[i-1]:
                continue
            for j in range(i+1,len(nums)-2):
                if j>0 and nums[j]==nums[j-1]:
                    continue
                l=j+1
                r=len(nums)-1
                while(l<r):
                    sum=nums[i]+nums[j]+nums[l]+nums[r]
                    if sum<target:
                        l+=1
                    if sum>target:
                        r-=1
                    if sum==target:
                        res.append([nums[i],nums[j],nums[l],nums[r]])
                        while l < r and nums[l] == nums[l + 1]:  # 兩個while語句用來快速移動指標,直到沒有出現相鄰重複數字
                            l += 1
                        while l < r and nums[r] == nums[r - 1]:
                            r -= 1
                        l+=1
                        r-=1
            return res
#最後還是看一下討論區大佬的程式碼吧,使用了遞迴的方式,可以適用於任意的N-sum的情況
def fourSum(self, nums, target):
    def findNsum(l, r, target, N, result, results):
        if r-l+1 < N or N < 2 or target < nums[l]*N or target > nums[r]*N:  # early termination
            return
        if N == 2: # two pointers solve sorted 2-sum problem
            while l < r:
                s = nums[l] + nums[r]
                if s == target:
                    results.append(result + [nums[l], nums[r]])
                    l += 1
                    while l < r and nums[l] == nums[l-1]:
                        l += 1
                elif s < target:
                    l += 1
                else:
                    r -= 1
        else: # recursively reduce N
            for i in range(l, r+1):
                if i == l or (i > l and nums[i-1] != nums[i]):
                    findNsum(i+1, r, target-nums[i], N-1, result+[nums[i]], results)

    nums.sort()
    results = []
    findNsum(0, len(nums)-1, target, 4, [], results)
    return results

遞迴的過程大概是這樣的:
一個N-sum問題可以不斷地轉化為(N-1)-Sum問題,比如說要求4-sum==0

  • 假如先確定第一個數字-2,那麼就轉化為去找3-sum==2,這時result=[-2],N=3
  • 3-sum=2,假如確定第二個數字是0,那麼去找2-sum==2,這時result=[-2,0],N=2
  • N=2就進入2sum的處理方式,直接找到2-sum==2的結果[0,2],這時results.append(result+[0,2]),相當於對results添加了一個[-2,0,0,2]
  • 中間如果遇到肯定不可能的情況就直接pass,以此類推就可以解決任意N-sum問題