LeetCode 15 - 三数之和

排序+双指针

首先对整个数组升序排序,便于对结果去重. 朴素算法是暴力枚举数组中的三个位置 (i,j,k),i<j<k,使得 nums[i]+nums[j]+nums[k]=0,复杂度为 O ( n 3 ) O(n^3) O(n3).

利用双指针算法进行优化,仍然枚举待选取的第一个数 nums[pos],然后在 [pos+1,n-1] 中找到两个下标 (le,ri),le<ri 使得 nums[pos]+nums[le]+nums[ri]=0 即可满足要求,算法流程如下:

  1. 如果 n<3 或数组内元素全部为正或全部为负,答案为空.
  2. 对原数组升序排序.
  3. 遍历排序后的数组:
    • nums[pos]>0,后面的元素一定也大于 0,因此不可能再有三个数相加和为 0,直接返回结果.
    • nums[pos-1]=nums[pos],直接跳过,避免重复解.
    • 令左指针 le=pos+1,右指针 ri=n-1,若 le<ri,则执行循环:
      • nums[pos]+nums[le]+nums[ri]=0,将这个三元组加入答案中,为了避免记录重复结果,将 leri 分别移动到下一处与当前值不相等的位置,继续寻找新的解.
      • nums[pos]+nums[le]+nums[ri]>0,将 ri 左移.
      • nums[pos]+nums[le]+nums[ri]<0,将 le 右移.

左指针 le 只向右移动,右指针 ri 只向左移动,因此总体时间复杂度为 O ( n 2 ) O(n^2) O(n2).

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ans;
        int len=nums.size();
        sort(nums.begin(),nums.end());
        if(len<3 || nums[0]>0 || nums[len-1]<0) return {};
        for(int pos=0;pos<len;++pos){
            if(nums[pos]>0) break;
            if(pos>0 && nums[pos-1]==nums[pos]) continue;
            int val=-nums[pos];
            int le=pos+1,ri=len-1;
            while(le<ri){
                if(nums[le]+nums[ri]==val){
                    ans.push_back({nums[pos],nums[le],nums[ri]});
                    while(le<ri && nums[le+1]==nums[le]) ++le;
                    while(le<ri && nums[ri-1]==nums[ri]) --ri;
                    ++le;--ri;
                }
                else{
                    if(nums[le]+nums[ri]<val) ++le;
                    else --ri;
                }
            }
        }
        return ans;
    }
};

个人 LeetCode 代码仓库地址:MyLeetCode,记录刷题成长之路,欢迎各位小伙伴们多多 star ~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值