相信大家都有做过两数之和,
题目链接: 15. 三数之和 - 力扣(LeetCode)
在文章的开始让我们回顾一下三数之和吧!
题目描述:
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请
你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0 。
解题思路:
首先要使形如a + b +c = 0,我们可以座一层循环,让i表示a,通过双指针表示另外两个数,left-->b,right-->c;在动手解题前一定要对数组做预处理,排序,这样可以避免很多麻烦,我们让i从数组下标第一个元素开始,left取i + 1;right取nums.length - 1;i不动,让两个指针移动,判断sum=a+b+c的值,当sum>0时,证明整体大了需要减小和,故使right--;当sum<0时,证明整体小了需要增大和,故使left++;sum=0即一组解。
整体思路就是这样,当其实有很多细节的地方,尤其是 去重,这也是解本题最关键的地方,我们需要对a b c去重,避免重复解。
对a去重: if(i>0 and nums[i]==nums[i-1]) continue;
对b c去重: if(right > left and nums[right] = nums[right--] ) right--;
if (right > left and nums[left] = nums[left++] ) left++;
上代码:
代码详解可看(强推,简单易懂,细节拉满): 梦破碎的地方!| LeetCode:15.三数之和_哔哩哔哩_bilibili
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
//预处理---》排序
Arrays.sort(nums);
for(int i=0;i < nums.length;i++){
if(nums[i] > 0) break;
// 对a去重
if(i > 0 && nums[i] == nums[i - 1]){continue;}
int left = i + 1;
int right = nums.length - 1;
// 指针移动条件
while(right > left){
int sum = nums[i] + nums[left] + nums[right];
if(sum > 0){right--;}
else if(sum < 0){left++;}
else{
// 先收获结果集在去重 确保至少收获一个结果集
res.add(Arrays.asList(nums[i],nums[left],nums[right]));
// 对b c去重 这里需要移动 不能用if做判断会漏解的****
while(right > left && nums[left] == nums[left+1]){left++;}
while(right > left && nums[right] == nums[right-1]){right--;}
right--;
left++;
}
}
}
return res;
}
}
这里在给出一个版本的参考:
如果有朋友实在理解不了的话这里给出一个n数之和的解决方案,直接就是背
c++版本:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
// n 为 3,从 nums[0] 开始计算和为 0 的三元组
return nSumTarget(nums, 3, 0, 0);
}
/* 注意:调用这个函数之前一定要先给 nums 排序 */
// n 填写想求的是几数之和,start 从哪个索引开始计算(一般填 0),target 填想凑出的目标和
vector<vector<int>> nSumTarget(
vector<int>& nums, int n, int start, int target) {
int sz = nums.size();
vector<vector<int>> res;
// 至少是 2Sum,且数组大小不应该小于 n
if (n < 2 || sz < n) return res;
// 2Sum 是 base case
if (n == 2) {
// 双指针那一套操作
int lo = start, hi = sz - 1;
while (lo < hi) {
int sum = nums[lo] + nums[hi];
int left = nums[lo], right = nums[hi];
if (sum < target) {
while (lo < hi && nums[lo] == left) lo++;
} else if (sum > target) {
while (lo < hi && nums[hi] == right) hi--;
} else {
res.push_back({left, right});
while (lo < hi && nums[lo] == left) lo++;
while (lo < hi && nums[hi] == right) hi--;
}
}
} else {
// n > 2 时,递归计算 (n-1)Sum 的结果
for (int i = start; i < sz; i++) {
vector<vector<int>>
sub = nSumTarget(nums, n - 1, i + 1, target - nums[i]);
for (vector<int>& arr : sub) {
// (n-1)Sum 加上 nums[i] 就是 nSum
arr.push_back(nums[i]);
res.push_back(arr);
}
while (i < sz - 1 && nums[i] == nums[i + 1]) i++;
}
}
return res;
}
};
java版本:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
// n 为 3,从 nums[0] 开始计算和为 0 的三元组
return nSumTarget(nums, 3, 0, 0);
}
/* 注意:调用这个函数之前一定要先给 nums 排序 */
// n 填写想求的是几数之和,start 从哪个索引开始计算(一般填 0),target 填想凑出的目标和
public List<List<Integer>> nSumTarget(
int[] nums, int n, int start, int target) {
int sz = nums.length;
List<List<Integer>> res = new ArrayList<>();
// 至少是 2Sum,且数组大小不应该小于 n
if (n < 2 || sz < n) return res;
// 2Sum 是 base case
if (n == 2) {
// 双指针那一套操作
int lo = start, hi = sz - 1;
while (lo < hi) {
int sum = nums[lo] + nums[hi];
int left = nums[lo], right = nums[hi];
if (sum < target) {
while (lo < hi && nums[lo] == left) lo++;
} else if (sum > target) {
while (lo < hi && nums[hi] == right) hi--;
} else {
res.add(new ArrayList<>(Arrays.asList(left, right)));
while (lo < hi && nums[lo] == left) lo++;
while (lo < hi && nums[hi] == right) hi--;
}
}
} else {
// n > 2 时,递归计算 (n-1)Sum 的结果
for (int i = start; i < sz; i++) {
List<List<Integer>>
sub = nSumTarget(nums, n - 1, i + 1, target - nums[i]);
for (List<Integer> arr : sub) {
// (n-1)Sum 加上 nums[i] 就是 nSum
arr.add(nums[i]);
res.add(arr);
}
while (i < sz - 1 && nums[i] == nums[i + 1]) i++;
}
}
return res;
}
}