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] ]
思路
在看到这道题之后,我第一反应是使用之前求三数之和那样求四数之和,结果也是可行,但是运行结果显示的时间复杂度太高。这里我先将我自己的解决思路写下来
时间复杂为O(n3),空间复杂为O(1)。
解决代码
1 class Solution:
2 def fourSum(self, nums, target):
3 """
4 :type nums: List[int]
5 :type target: int
6 :rtype: List[List[int]]
7 """
8 if len(nums) < 4: # 异常情况,小于四个直接返回
9 return []
10 if len(nums) == 4 and sum(nums) == target:
11 return [nums]
12 nums.sort() # 先进行排序
13 res = []
14 for i in range(len(nums)-3): # 第一个下标
15 if i > 0 and nums[i] == nums[i-1]: # 遇到重复的直接跳过
16 continue
17 for j in range(i+1, len(nums)-2): # 第二个下标
18 if j > i+1 and nums[j] == nums[j-1]: # 遇到重复直接跳过
19 continue
20 start, end = j+1, len(nums)-1 # 另外两个下标,指向头和尾部
21 while start < end:
22 tem = nums[i] + nums[j] + nums[start] + nums[end]
23 if tem - target > 0: # 进行判断,选择相应的移位
24 end -= 1
25 elif tem - target < 0:
26 start += 1
27 else: # 找到符合条件的四个数字。
28 res.append([nums[i], nums[j], nums[start], nums[end]]) # 将其添加进结果集中
29 while start < end and nums[start] == nums[start+1]: # 相同元素直接跳过。
30 start += 1
31 while start < end and nums[end] == nums[end-1]: # 相同元素直接跳过
32 end -= 1
33 start += 1
34 end -= 1
35 return res
改进
上面的算法,在实现之后效率太低,以至于运行结果之超过了百分之10的用户。但是由于自己也想不出什么好的办法,因此取讨论区看了别人的写法,不得不说确实很厉害。下面写上别人给出了一个解决方法,这个方法可以解决N数和的问题。
解决思路以及代码
这个问题他的解决思路主要是通过分解,将N数和的问题转化为两数和的问题(递归),并且通过传递变量来记录满足结果的条件。
1 def fourSum(self, nums, target):
2 nums.sort()
3 results = []
4 self.findNsum(nums, target, 4, [], results) #因为本题是4数之和的问题,所以传入的参数是4,并且将保存满足条件的数字的变量进行传递
5 return results
6
7 def findNsum(self, nums, target, N, result, results):
8 if len(nums) < N or N < 2: return # 数组的长度小于N(N数之和)时或者小于2时,直接返回条件。
10 # solve 2-sum
11 if N == 2: # 当N == 2 时,进行判断, 里面的步骤和三数问题中的步骤一样。
12 l,r = 0,len(nums)-1
13 while l < r:
14 if nums[l] + nums[r] == target:
15 results.append(result + [nums[l], nums[r]])
16 l += 1
17 r -= 1
18 while l < r and nums[l] == nums[l - 1]:
19 l += 1
20 while r > l and nums[r] == nums[r + 1]:
21 r -= 1
22 elif nums[l] + nums[r] < target:
23 l += 1
24 else:
25 r -= 1
26 else: # N大于2时进行递归,分解
27 for i in range(0, len(nums)-N+1): # careful about range # 第一个指针位置
28 if target < nums[i]*N or target > nums[-1]*N: # 意外情况判定,因为数组是已经排好序的,当第一个元素(最小)乘
29 break # 以N时,还比target大,那说明,后面的都不满足,直接返回。后面同理。
30 if i == 0 or i > 0 and nums[i-1] != nums[i]: #recursively reduce N #从第一个看是遍历,并将相应额结果进行传递。
31 self.findNsum(nums[i+1:], target-nums[i], N-1, result+[nums[i]], results)
32 return