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