LeetCode Notes_#18 4Sum

LeetCode Notes_#18 4Sum

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问题

转载于:https://www.cnblogs.com/Howfars/p/9964918.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值