摘自labuladong
nums = [1,3,1,2,2,3], target = 4
问题一:
[1,3] 和 [3,1] 就算重复,通过先排序再双指针可实现结果的按顺序排列。
问题二:
nums = [1,1,1,2,2,3,3], target = 4
[1,3] 肯定会重复
出问题的地方在于 sum == target 条件的 if 分支,当给 res 加入一次结果后,lo 和 hi 不应该改变 1 的同时,还应该跳过所有重复的元素:
// 记录索引 lo 和 hi 最初对应的值
int left = nums[lo], right = nums[hi];
...
// 找到一组解后,跳过所有重复的元素
while (lo < hi && nums[lo] == left) lo++;
while (lo < hi && nums[hi] == right) hi--;
时间复杂度是 O(N),而排序的时间复杂度是 O(NlogN),所以这个函数的时间复杂度是 O(NlogN)。
现在想找和为 target 的三个数字,那么对于第一个数字,可能是什么?
nums 中的每一个元素 nums[i] 都有可能!
那么,确定了第一个数字之后,剩下的两个数字可以是什么呢?
其实就是和为 target - nums[i] 的两个数字呗,那不就是 twoSum 函数解决的问题么
需要把 twoSum 函数稍作修改即可复用。
// 已排序
function twoSum(le,ri,nums,target){
let arr = []
while(le<ri){
let i = nums[le], j = nums[ri]
if (i+j < target){
while(le<ri && nums[le]==i) le++;
} else if(i+j > target){
while(le<ri && nums[ri]==j) ri--;
} else{
arr.push([i,j])
while(le<ri && nums[le]==i) le++; // 去重
while(le<ri && nums[ri]==j) ri--; // 去重
}
}
return arr
}
var threeSum = function(nums) {
let res = [], len = nums.length-1
if(len < 2) return res;
nums.sort((a, b) => a - b);
for (let i = 0; i <= len ; i++){
let tmp = twoSum(i+1,len,nums,0-nums[i])
tmp.forEach(val => res.push([nums[i],...val]))
while (i < len && nums[i] == nums[i + 1]) i++; // 去重
}
return res;
};
不使用多个函数,参考三数之和,四数之和
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var fourSum = function(nums, target) {
const length = nums.length;
const res = [];
nums.sort((a,b)=>a-b);
if(length < 4) return res;
for(let i=0; i<length-3; i++) {
for(let j=i+1; j<length-2; j++) {
let left = j+1, right = length-1;
const presum = nums[i] + nums[j]
while(left < right) {
let le = nums[left], ri = nums[right];
const sum = presum + le + ri
if(sum == target) {
res.push([nums[i], nums[j], nums[left], nums[right]]);
while(left < right && nums[left]==le) left++; // 去重
while(left < right && nums[right]==ri) right--; // 去重
}else if(sum > target){
while(left < right && nums[right]==ri) right--;
}else{
while(left < right && nums[left]==le) left++;
}
}
while (j < length-3 && nums[j] == nums[j + 1]) j++; // 去重
}
while (i < length-4 && nums[i] == nums[i + 1]) i++; // 去重
}
return res;
};