一、三数之和
题目:
给你⼀个包含 n 个整数的数组 nums ,判断 nums 中是否存在三个元素 a , b , c ,使得 a + b + c = 0 ?请你找出所有满⾜条件且不重复的三元组。注意:一个三元组中元素不能重复,对应的索引不同,值是可以相同的
示例:
给定数组 nums =[1, 0, -1, 0, 0] ,和 target = 0 。满⾜要求的三元组集合为:[[-1, 0, 1 ] ,[0, 0, 0 ]]
要点:
- 双指针搭配排序数组
-
固定第一个数,然后再设置两个指针,左指针 p 指向固定的数的后⾯那个值, 右指针 q 指向最后⼀个值,两个指针相向⽽⾏。
-
根据 arr[ p ] + arr[ q ] 和 target - arr[ i ]的大小关系,移动pq指针
-
注意重复元素的跳过问题——指针每次更新都需要检查
// 三数之和
function threeSum(arr, target) {
arr.sort((a, b) => a - b);
const res = [];
const len = arr.length;
for (let i = 0; i < len - 2; i++) {
// 如果有重复数字就跳过
if (i > 0 && arr[i] === arr[i - 1]) {
continue;
}
const remain = target - arr[i];
// 初始化双指针
let p = i + 1;
let q = len - 1;
while (p < q) {
const sum = arr[p] + arr[q];
if (sum === remain) {
res.push([arr[i], arr[p++], arr[q--]]);
// 重复元素跳过
while (p < q && arr[p] === arr[p - 1]) {
p++;
}
while (p < q && arr[q] === arr[q + 1]) {
q--;
}
} else if (sum < remain) {
p++;
// 重复元素跳过
while (p < q && arr[p] === arr[p - 1]) {
p++;
}
} else {
q--;
// 重复元素跳过
while (p < q && arr[q] === arr[q + 1]) {
q--;
}
}
}
}
return res;
}
二、四数之和
题目基本同三数之和,只是换成四个数之和了
要点:
- 固定两个数字,然后再初始化两个指针,两个指针的移动同三数之和类似
- 做完题之后,考虑一些快速结束的情况,提高性能
// 四数之和
function fourSum(arr, target) {
const res = [];
arr.sort((a, b) => a - b);
const len = arr.length;
for (let i = 0; i < len - 3; i++) {
// 如果有重复数字就跳过
if (i > 0 && arr[i] === arr[i - 1]) {
continue;
}
// 三数之和
for (let j = i + 1; j < len - 2; j++) {
// 如果有重复数字就跳过
if (j > i + 1 && arr[j] === arr[j - 1]) {
continue;
}
// 快速跳出,提高性能
if (arr[i] + arr[i + 1] + arr[i + 2] + arr[i + 3] > target) {
break;
}
const remain = target - arr[i] - arr[j];
// 初始化双指针
let p = j + 1;
let q = len - 1;
while (p < q) {
const sum = arr[p] + arr[q];
if (sum === remain) {
res.push([arr[i], arr[j], arr[p++], arr[q--]]);
// 重复元素跳过
while (p < q && arr[p] === arr[p - 1]) {
p++;
}
while (p < q && arr[q] === arr[q + 1]) {
q--;
}
} else if (sum < remain) {
p++;
// 重复元素跳过
while (p < q && arr[p] === arr[p - 1]) {
p++;
}
} else {
q--;
// 重复元素跳过
while (p < q && arr[q] === arr[q + 1]) {
q--;
}
}
}
}
}
return res;
}