LeetCode 15. 3Sum【左右指针模板题】⭐⭐⭐⭐⭐

文章目录

  • 题目描述
  • 知识点
  • 结果
  • 实现
    • 码前思考
    • 代码实现
    • 码后反思
    • 参考思路
  • 二刷代码

题目描述

LeetCode 15. 3Sum【左右指针模板题】⭐⭐⭐⭐⭐_第1张图片

知识点

排序+双指针

结果

在这里插入图片描述

实现

码前思考

这道题我没有做出来。。。

  1. 暴力思考:求a+b+c = 0,最直观的方法就是枚举a,b,c,也就是组合数 C n 3 C_n^3 Cn3,这样的会使时间复杂度达到 O ( n 3 ) O(n^3) O(n3),显然不可取;
  2. 既然不能暴力,那么我们需要将原问题再次进行剖析,要另辟蹊径(转换问题,等价问题是解决暴力的首选思想),所谓a+b+c = 0,其实就是a = -b-c。也就是对a,我们要去寻找-b-c即可。
  3. 但是,如果我们直接去找,那么这样的时间复杂度仍然是 O ( n 3 ) O(n^3) O(n3)(枚举a O ( n ) O(n) O(n)乘上枚举-b-c O ( n 2 ) O(n^2) O(n2)),但是如果我们对原数组nums进行排序,然后使用 双指针 ,那么枚举-b-c的时间复杂度就变成了 O ( n ) O(n) O(n),这样总体时间复杂度就为 O ( n 2 ) O(n^2) O(n2)了;
  4. 关于不能有重复解的问题,利用上面的排序,我们就可以解决了,真是一举两得。否则,不用排序也挺难解决的,我没写出来就是卡在没有想到排序。
  5. 另外一个小技巧就是,当我们排序完之后,如果遍历到nums[k]大于0时,我们就可以返回结果了,因为后面的数都不可能满足条件了。

代码实现

//采用O(n^2)+hash的解法
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;

        //特判一些特殊的情况:数组长度小于3的情况
        int size = nums.size();
        if(size < 3){
            return res;
        }

        //通过排序来解决重复解的问题
        sort(nums.begin(),nums.end());

        //使用双指针来解决问题
        for(int k=0;k<size;k++){
            //用于已经排序,所以当当前数字nums[k]为整数时,肯定可以停止了
            if(nums[k] > 0){
                break;
            }

            //去除重复解,当nums[k]==nums[k-1]时,说明可以跳过这个k
            if(k>0&&nums[k]==nums[k-1]){
                continue;
            }

            //开始双指针操作
            int target = 0 - nums[k];
            int i= k+1;
            int j= size-1;
            //只要两个指针没有相遇,代表还在进行筛选
            while(i<j){
                if(nums[i]+nums[j] == target){
                    vector<int> tmp;
                    res.push_back({nums[k],nums[i],nums[j]});
                    //排除重复解的情况,即nums[i+1]==nums[i],nums[j-1]==nums[j]
                    while(i<j && nums[i+1] == nums[i]){
                        i++;
                    }
                    while(i<j && nums[j-1] == nums[j]){
                        j--;
                    }
                    i++;
                    j--;
                }else if(nums[i]+nums[j] <target){//意味着i要右移
                    i++;
                }else{  //意味着j要左移
                    j--;
                }
            }

        }

        return res;
    }
};

码后反思

  1. 之前做的时候是遍历a+b,然后利用hash找-c的,结果卡在重复解上,现在想想,只要排个序就能解决这个问题了,以后尝试一下,时间复杂度也是 O ( n 2 ) O(n^2) O(n2)这个想法就没有用到双指针了!
  2. 其实,我不知道双指针是什么,我去学学,查漏补缺呀!
  3. ⭐⭐⭐⭐⭐如果找某一个特定元素,一个指针就够了。如果是找两个元素满足一定关系(比如求和等于特定值),需要双指针, 当然前提是数组有序。

参考思路

LeetCode 第 15 号问题:三数之和

二刷代码

二刷的时候又忘记左右指针该怎么用了,
所谓左右指针用在数组上,通常都是需要是排序过后的数组。这道题目和之前的Two Sum的题目是一模一样的。

//采用双指针进行解题,使用的是左右指针
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int len = nums.size();
        vector<vector<int>> res;

        if(len<3){
            return res;
        }

        sort(nums.begin(),nums.end());

        for(int i=0;i<len;i++){
            if(nums[i]>0){
                break;  //说明后面不可能了
            }
            if(i>0&&nums[i-1]==nums[i]){
                continue;
            }
            int cur = nums[i];
            int target = -cur;
            int left = i+1;
            int right = len-1;
            while(left<right){
                if(nums[left]+nums[right]==target){
                    vector<int> vt = {cur,nums[left],nums[right]};
                    res.push_back(vt);
                    //排除重复的情况
                    while(left<right&&nums[left+1]==nums[left]){
                        left++;
                    }
                    while(left<right&&nums[right-1]==nums[right]){
                        right--;
                    }
                    left++;
                    right--;
                }else if(nums[left]+nums[right]<target){
                    left++;
                }else{
                    right--;
                }
            }
        }
        return res;
    }
};

你可能感兴趣的:(#,双指针,leetcode,数据结构,算法,双指针)