相信大家都有做过两数之和,
题目链接: 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,且数组大小不应该小于 nif (n < 2 || sz < n) return res;// 2Sum 是 base caseif (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] 就是 nSumarr.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,且数组大小不应该小于 nif (n < 2 || sz < n) return res;// 2Sum 是 base caseif (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] 就是 nSumarr.add(nums[i]);res.add(arr);}while (i < sz - 1 && nums[i] == nums[i + 1]) i++;}}return res;}
}