思路
思路和 15. 三数之和 一样,排序后,枚举 nums[a]
作为第一个数,枚举 nums[b]
作为第二个数,那么问题变成找到另外两个数,使得这四个数的和等于 target
,这可以用双指针解决。
优化思路也和视频中讲的一样,对于 nums[a]
的枚举:
设
s=nums[a]+nums[a+1]+nums[a+2]+nums[a+3]
。如果s>target
,由于数组已经排序,后面无论怎么选,选出的四个数的和不会比s
还小,所以后面不会找到等于target
的四数之和了。所以只要s>target
,就可以直接break
外层循环了。设
s=nums[a]+nums[len−3]+nums[len−2]+nums[len−1]
。如果s<target
,由于数组已经排序,nums[a]
加上后面任意三个数都不会超过s
,所以无法在后面找到另外三个数与nums[a]
相加等于target
。但是后面还有更大的nums[a]
,可能出现四数之和等于target
的情况,所以还需要继续枚举,continue
外层循环。如果
a>0
且nums[a]=nums[a−1]
,那么nums[a]
和后面数字相加的结果,必然在之前算出过,所以无需执行后续代码,直接continue
外层循环。(可以放在循环开头判断。)
对于 nums[b]
的枚举(b
从 a+1
开始),也同样有类似优化:
设
s=nums[a]+nums[b]+nums[b+1]+nums[b+2]
。如果s>target
,由于数组已经排序,后面无论怎么选,选出的四个数的和不会比s
还小,所以后面不会找到等于target
的四数之和了。所以只要s>target
,就可以直接break
。设
s=nums[a]+nums[b]+nums[len−2]+nums[len−1]
。如果s<target
,由于数组已经排序,nums[a]+nums[b]
加上后面任意两个数都不会超过s
,所以无法在后面找到另外两个数与nums[a]
和nums[b]
相加等于target
。但是后面还有更大的nums[b]
,可能出现四数之和等于 target 的情况,所以还需要继续枚举,continue
。如果
b>a+1
且nums[b]=nums[b−1]
,那么nums[b]
和后面数字相加的结果,必然在之前算出过,所以无需执行后续代码,直接continue
。注意这里b>a+1
的判断是必须的,如果不判断,对于示例 2 这样的数据,会直接continue
,漏掉符合要求的答案。
代码
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var fourSum = function (nums, target) {
nums.sort((a, b) => a - b)
const len = nums.length
const ans = []
for (let a = 0; a < n - 3; a++) {
// 枚举第一个数
const x = nums[a]
if (a > 0 && x === nums[a - 1]) continue // 跳过重复数字
if (x + nums[a + 1] + nums[a + 2] + nums[a + 3] > target) break
if (x + nums[len - 3] + nums[len - 2] + nums[len - 1] < target) continue
for (let b = a + 1; b < len - 2; b++) {
// 枚举第二个数
const y = nums[b]
if (b > a + 1 && y === nums[b - 1]) continue // 跳过重复数字
if (x + y + nums[b + 1] + nums[b + 2] > target) break
if (x + y + nums[len - 2] + nums[len - 1] < target) continue
let L = b + 1,
R = len - 1
while (L < R) {
// 双指针枚举第三个数和第四个数
const s = x + y + nums[L] + nums[R] // 四数之和
if (s > target) R--
else if (s < target) L++
else {
// s == target
ans.push([x, y, nums[L], nums[R]])
for (L++; L < R && nums[L] === nums[L - 1]; L++);
for (R--; R > L && nums[R] === nums[R + 1]; R--);
}
}
}
}
return ans
}