题目 #
Given an array nums of n integers, return an array of all the unique quadruplets [nums[a], nums[b], nums[c], nums[d]] such that:
- 0 <= a, b, c, d < n
- a, b, c, and d are distinct.
- nums[a] + nums[b] + nums[c] + nums[d] == target
You may return the answer in any order.
Example 1:
Input: nums = [1,0,-1,0,-2,2], target = 0
Output: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
Example 2:
Input: nums = [2,2,2,2,2], target = 8
Output: [[2,2,2,2]]
Constraints:
- 1 <= nums.length <= 200
- $-10^9 <= nums[i] <= 10^9$
- $-10^9 <= target <= 10^9$
思路1 暴力破解 #
分析 #
- 所有人的第一想法,4重循环直接做,然后去个重
思路2 两轮循环+双指针 #
分析 #
- 第一个优化,因为要去重,那直接排个序,然后保证顺序的情况下就不会有重复的数字了,循环时考虑每一个元素不要取到相同的就好了
- 第二个优化,最后两轮循环其实可以参考两个元素之和,使用双指针进行,将 $O(n^2)$ 变成 $O(n)$
代码 #
1func fourSum(nums []int, target int) [][]int {
2 // 先排序
3 sort.Ints(nums)
4 result := make([][]int, 0)
5 n := len(nums)
6 // 然后前两个用循环套
7 // 第一个元素首先不能和随后的三个相加已经大于target了,毕竟排了序,大于后面随便选都不可能等于target
8 for i := 0; i < n-3 && nums[i]+nums[i+1]+nums[i+2]+nums[i+3] <= target; i++ {
9 // 下一轮循环时第一个元素必须选和当前不一样的,否则就重复了
10 // 并且不能和最大的三个相加还比target小,否则同样无法满足选四个相加等于target
11 if nums[i]+nums[n-1]+nums[n-2]+nums[n-3] < target || (i > 0 && nums[i] == nums[i-1]) {
12 continue
13 }
14 for j := i + 1; j < n-2 && nums[i]+nums[j]+nums[j+1]+nums[j+2] <= target; j++ {
15 if nums[i]+nums[j]+nums[n-1]+nums[n-2] < target || (j > i+1 && nums[j] == nums[j-1]) {
16 continue
17 }
18 // 剩余两个数使用双指针找
19 for l, r, t := j+1, n-1, target-nums[i]-nums[j]; r > l; {
20 tmp := nums[r] + nums[l] - t
21 if tmp == 0 {
22 result = append(result, []int{nums[i], nums[j], nums[l], nums[r]})
23 }
24 if tmp >= 0 {
25 for r--; r > l && nums[r] == nums[r+1]; r-- {
26 }
27 }
28 if tmp <= 0 {
29 for l++; r > l && nums[l] == nums[l-1]; l++ {
30 }
31 }
32 }
33 }
34 }
35 return result
36}