思路:
我们对数组进行从小到大的排列
然后使用双指针 num[i] + num[left] + num[right] = target
剪枝操作: 元素都是大于0的, 当第一个元素如果大于target那么就直接结束
题目要求:不能出现重复的数组 我们需要对每个位置的元素进行去重(i left right)
当对i进行去重时,应该使用 num[i] === num[i-1] 不能使用num[i] === num[i+1],因为left在i的右边,我们需要的是每个位置的元素不同,而不是结果的数组里不能有重复
对left去重 使用 num[left] === num[left+1] left++
对right去重 num[right] === num[right-1] right --;
var threeSum = function(nums) {
const res = [], len = nums.length
// 将数组排序
nums.sort((a, b) => a - b)
for (let i = 0; i < len; i++) {
let l = i + 1, r = len - 1, iNum = nums[i]
// 数组排过序,如果第一个数大于0直接返回res
if (iNum > 0) return res
// 去重
if (iNum == nums[i - 1]) continue
// 因为是3个数,所以不是left <= right
while(l < r) {
let lNum = nums[l], rNum = nums[r], threeSum = iNum + lNum + rNum
// 三数之和小于0,则左指针向右移动
if (threeSum < 0) l++
else if (threeSum > 0) r--
else {
res.push([iNum, lNum, rNum])
// 去重
while(l < r && nums[l] == nums[l + 1]){
l++
}
while(l < r && nums[r] == nums[r - 1]) {
r--
}
l++
r--
}
}
}
return res
};
思路和上面一样,有一个区别就是 会有负值的情况,所以不能直接和上面一样的剪枝操作,应该在大于0的情况才能剪枝 num[k]>0 && target>0 && num[k] > target
var fourSum = function(nums, target) {
const len = nums.length;
if(len < 4) return [];
nums.sort((a, b) => a - b);
const res = [];
for(let i = 0; i < len - 3; i++) {
if (nums[i] > target && nums[i] >= 0) {
break; // 这里使用break,统一通过最后的return返回(第一层剪枝)
}
// 去重nums[i]
if(i > 0 && nums[i] === nums[i - 1]) continue;
for(let j = i + 1; j < len - 2; j++) {
// 第二次剪枝
if(num[i] + nums[j] > target && nums[k] + nums[i] >= 0{
break;
}
// 去重nums[j]
if(j > i + 1 && nums[j] === nums[j - 1]) continue;
let l = j + 1, r = len - 1;
while(l < r) {
const sum = nums[i] + nums[j] + nums[l] + nums[r];
if(sum < target) { l++; continue}
if(sum > target) { r--; continue}
res.push([nums[i], nums[j], nums[l], nums[r]]);
// 对nums[left]和nums[right]去重
while(l < r && nums[l] === nums[++l]);
while(l < r && nums[r] === nums[--r]);
}
}
}
return res;
};