leetcode15三数之和(重点讲去重)

本文主要讲解三数之和的要点与细节,主要讲解利用双指针的方法解决,按照步骤一步步思考方便理解

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != 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;
            //去重a
            if (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,添加进resul
                    result.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和c
                    right--;
                    left++;
                }
            }
        }
        return result;
    }
}

  • 48
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值