@(labuladong的算法小抄)[nSum]
leetcode 15. 三数之和
题目描述
解题思路
参考:labuladong的算法小抄P319
套用nSum的解题框架
为什么nSum框架,从nums[start]开始?
由于不允许重复,所以从start处开始,参考leetcode 77. 组合
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
/* n为3,从nums[0]开始,计算和为0的三元组 */
return nSumEqualsTarget(nums, 3, 0, 0);
}
/* nSum框架,从nums[start]开始,计算和为target的n元组 */
private List<List<Integer>> nSumEqualsTarget(int[] nums, int n, int start, int target) {
int sz = nums.length;
List<List<Integer>> res = new LinkedList<>();
/* 至少是2Sum,且数组大小不应该小于n */
if (n < 2 || sz < n) return res;
/* 2Sum是base case */
if (n == 2) {
/* 双指针 */
int low = start, high = sz - 1;
/* 不能重复取元素,所以是小于号 */
while (low < high) {
int sum = nums[low] + nums[high];
/* 记录索引low和high最初对应的值,方便跳过重复元素 */
int left = nums[low], right = nums[high];
if (sum == target) {
/* 把二元组{left, right}添加到res中 */
List<Integer> tmp = new LinkedList<>();
tmp.add(left);
tmp.add(right);
res.add(tmp);
/* 两边跳过重复元素 */
while (low < high && nums[low] == left) low++;
while (low < high && nums[high] == right) high--;
} else if (sum < target) {
/* 左指针跳过重复元素 */
while (low < high && nums[low] == left) low++;
} else if (sum > target) {
/* 右指针跳过重复元素 */
while (low < high && nums[high] == right) high--;
}
}
} else {
/* n>2时,递归计算(n-1)Sum的结果 */
for (int i = start; i < sz; i++) {
/* 对target-nums[i]计算(n-1)Sum */
List<List<Integer>> sub = nSumEqualsTarget(nums, n - 1, i + 1, target - nums[i]);
for (List<Integer> arr : sub) {
/* 如果存在满足条件的(n-1)元组,则再加上nums[i]就是nSum */
arr.add(nums[i]);
res.add(arr);
}
/* 跳过重复元素,最终i会停在该重复元素的最后一个 */
while (i < sz - 1 && nums[i] == nums[i + 1]) i++;
}
}
return res;
}
}