本文主要讲解三数之和的要点与细节,主要讲解利用双指针的方法解决,按照步骤一步步思考方便理解
给你一个整数数组
nums
,判断是否存在三元组[nums[i], nums[j], nums[k]]
满足i != j
、i != k
且j != k
,同时还满足nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为
0
且不重复的三元组。注意:答案中不可以包含重复的三元组
c++与java代码如下,末尾
具体要点:
1. 本题核心要点在于,三元组里面的数的顺序是不重要的,结果不能包含重复的三元组
这就要求我们要对结果进行去重的操作,也是本题最需要考虑清楚的
2. 这道题我们可以采用双指针(滑动窗口)或者 哈希表的方法来处理,但是相比于哈希表,双指针考虑去重要更简单一点,我们先重点讲解双指针的解法
3. 一直说去重去重,到底是什么呢?
去重的核心操作是:判断上一个或者下一个值是否等于当前值,若等于,就跳过,再去判断下一个
4. 所以我们第一步就要对数组进行排序,目的是让相同的值都挨在一起,方便去重
5. 然后我们for循环遍历数组,获取a的值,即nums[i]
然后我们需要考虑一下a去重的问题:如果 i 和 i-1 位置的值相等,那么就跳过(这里有小细节最后讲)
if (i > 0 && nums[i] == nums[i - 1]) continue;
6. 接着在a=nums[i]条件下,定义两个指针 left = i + 1 和 right = nums.size() - 1,其值分别代表b和c
记录 sum=nums[i] + nums[left] + nums[right]
然后就开始滑动,通过判断sum和0的大小
若sum>0则right--
若sum<0则left++
若sum==0则把i、left、right加入结果
7. 当我们 “sum==0则把i、left、right加入结果”之后,我们需要向中间移动left和right,但是移动后位置会出现和上个位置重复值的情况,此时我们就要对 b 和 c 去重了
//对b去重,此时判断的是下一个位置,因为要确定移动到哪
while (left < right && nums[right] == nums[right - 1]) right--;
//对c去重,此时判断的是下一个位置,因为要确定移动到哪
while (left < right && nums[left] == nums[left + 1]) left++;
//直到没有重复的,我们就正常移动
left++;
right--;
最后返回result即可
8. 细节问题
a,b,c去重操作一样吗,好像还不太一样
a比较的是 nums[i] 与 nums[i - 1]。是和移动的上一个进行比较
b和c比较的是 nums[right] == nums[right - 1] 与 nums[left] == nums[left + 1]。是和移动的下一个位置进行比较(虽然right是-,left是+,但是他们是往中间移动)
为什么a的i不能和i+1比较呢?
因为,i+1的位置放的是left呀(b)! a不需要和b进行去重呀!abc三者重复是可以的
理解不了?举个例子:nums={-1,-1,-2}
a是第一个-1,如果i和i+1比较,下一个也是-1,就跳过咯,a直接指向第二个-1(left和right也取不到第一个-1),就错了
c++代码:
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {//定义一个vector保存结果vector<vector<int>> result;//对数组排序sort(nums.begin(), nums.end());for (int i = 0; i < nums.size(); i++) {if (nums[i] > 0)return result;//对a去重,此时判断的是上一个位置,如果判断的是下一位,就大错特错,因为下一位放的是left,left和i相等是不影响结果的if (i > 0 && nums[i] == nums[i - 1]) continue;//定义两个指针int left = i + 1;int right = nums.size() - 1;//执行滑动操作while (left < right) {int sum=nums[i] + nums[left] + nums[right];if (sum > 0) {right--; }else if (sum < 0) {left++;}else {result.push_back(vector<int>{nums[i], nums[left], nums[right]});//对b去重,此时判断的是下一个位置,因为要确定移动到哪while (left < right && nums[right] == nums[right - 1]) right--;//对c去重,此时判断的是下一个位置,因为要确定移动到哪while (left < right && nums[left] == nums[left + 1]) left++;left++;right--;}}}return result;}
};
java代码
class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result = new ArrayList<>();//先排序Arrays.sort(nums);for (int i = 0; i < nums.length; i++) {if (nums[i] > 0) return result;//去重aif (i > 0 && nums[i] == nums[i - 1]) continue;//定义双指针int left = i + 1, right = nums.length - 1;//双指针滑动while (left < right) {int sum = nums[i] + nums[left] + nums[right];if(sum>0){right--;}else if (sum < 0) {left++;}else {//等于0,添加进resulresult.add(Arrays.asList(nums[i], nums[left], nums[right]));//添加完成后,移动b和c,准备对下一个位置循环,在此之前,要先去重操作,不然移动了还会有重复的while (left < right && nums[left] == nums[left + 1]) left++;while (left < right && nums[right] == nums[right - 1]) right--;//去重完成,移动b和cright--;left++;}}}return result;}
}