Leetcode 15 -- 双指针

题目描述

三数之和

思路

参考

先不考虑重复的问题。从暴力出发,我们需要使用三重循环,会超速。
对于数组循环的优化问题,双指针很常用。
双指针(又称为快慢指针)可以将一个二重循环优化为一重,因此我们可以用双指针优化。
我们可以以此枚举每一个点作为第一个数,从后面寻找第二个和第三个数。

关于去重:

首先不管三七二十一,先排序!
首先要知道,什么时候会发生重复!
参考回溯中树层去重的例子,当一个集合的子集相同的时候,后面就可能出现重复。
因此,我们的目标是消除重复的子集。
这和树层去重基本类似:if(i > 0 && nums[i] == nums[i - 1]) continue
当一个数和前一个数相同的时候,如果前一个数没有选,我们说此时子集重复了。但这里我们并没有判断前一个数有没有选。
这是因为不需要判断,因为当前的nums[i]是起点,之前的数肯定没选。

代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n = nums.size();
        if(n < 3)   return {};

        sort(nums.begin(), nums.end());
        // for(auto &x : nums) cout << x << ' ';
        cout << endl;
        vector<vector<int>> res;

        for(int i = 0; i < n; i ++ ) {
            if(nums[i] > 0) break;
            if(i > 0 && nums[i] == nums[i - 1]) continue; // 子集:{x..},{x..}

            int l = i + 1, r = n - 1;
            while(l < r) { // 不能 l<=r, 否则他们就是同一个数,而我们需要两个数
                if(nums[l] + nums[r] + nums[i] > 0)    {
                    while(r > l && nums[l] + nums[r] + nums[i] > 0)  r -- ;
                }
                else if(nums[l] + nums[r] + nums[i] < 0) {
                    while(r > l && nums[l] + nums[r] + nums[i] < 0)  l ++ ;
                }   
                else { //if(nums[l] + nums[r] + nums[i] == 0) 
                    res.push_back(vector<int>{nums[i], nums[l], nums[r]});
                    l ++ , r -- ;
                    while(l < r && nums[l] == nums[l - 1])   l ++ ; // 子集:{x,y,z},{x,y,z},y重复
                    while(l < r && nums[r] == nums[r + 1])   r -- ; // 子集:{x,y,z},{x,y,z},z重复
                }
            }
        }

        return res;
    }
};
posted @ 2022-10-11 15:11  光風霽月  阅读(16)  评论(0编辑  收藏  举报