LeetCode 015 3Sum

本文探讨了经典的三数之和问题,通过多种方法寻找数组中三个数相加为零的所有唯一组合。介绍了两种指针技术和优化技巧,包括如何避免重复结果及提高搜索效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

15. 3Sum

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note: The solution set must not contain duplicate triplets.

For example, given array S = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
    }
};
解题思路:
  • 自己的解题思路
一开始打算用两个指针技术,进行求解。但是遇到下一步怎么走问题。
最后用了一个重复查询的方法,进行搜索。
  • 别人的解题思路
别人用的两个指针技术与我的不同,他是先确定一点,然而左右搜。我的则是先确定前后两点,然后再确定一点。
学习收获:
  • 对于不重复的,可以采用pre-check技术,直接转到下一个不重复的值。
  • 知道reserve()对运行时间的影响
  • 熟悉了unique(),resize(),distance()[<iterator>里面],以及erase()操作。
  • 对于vectorerase()   只改变size,而且分2个版本:(1)删除1个值 (2)删除一个区间。
//操作1
auto it = unique(res.begin(), res.end());
    res.resize(distance(res.begin(), it));
    //操作2
auto it = unique(res.begin(), res.end());
res.erase(it, res.end());
附件:程序
1、自己的程序:
版本1:运用下标,进行搜索
vector<vector<int>> threeSum(vector<int>& nums)
{
    bool myComp(vector<int> & a, vector<int> & b);
    sort(nums.begin(), nums.end());
    vector<int> temp(3);
    vector<vector<int>> res;
    auto size = nums.size();
    if(size >= 3)
    {
        decltype(size) st = 0;
        decltype(size) ed = size - 1;
        while((ed - st) >= 1 && nums[st] <= 0 && nums[ed] >= 0)
        {
            while((ed - st) >= 1 && nums[ed] >= 0)
            {
                int wt = -(nums[st] + nums[ed]);
                auto mid = find(nums.begin() + st + 1, nums.begin() + ed, wt);
                if(mid != nums.begin() + ed)
                {
                    temp[0] = nums[st];
                    temp[1] = *mid;
                    temp[2] = nums[ed];
                    res.push_back(temp);
                }
                --ed;
            }
            while((ed - st) >= 1 && nums[st] == nums[st + 1])
            {
                ++st;
            }
            ++st;
            ed = size - 1;
        }
    }
    auto it = unique(res.begin(), res.end());
    res.resize(distance(res.begin(), it));
    return res;
}
改进版1:改进后的程序,不再需要unique()操作
vector<vector<int>> threeSum(vector<int>& nums)
{
    bool myComp(vector<int> & a, vector<int> & b);
    sort(nums.begin(), nums.end());
    vector<int> temp(3);
    vector<vector<int>> res;
    res.reserve(100);
    auto size = nums.size();
    if(size >= 3)
    {
        decltype(size) st = 0;
        decltype(size) ed = size - 1;
        while((ed - st) >= 1 && nums[st] <= 0 && nums[ed] >= 0)
        {
            while((ed - st) >= 1 && nums[ed] >= 0)
            {
                int wt = -(nums[st] + nums[ed]);
                auto mid = find(nums.begin() + st + 1, nums.begin() + ed, wt);
                if(mid != nums.begin() + ed)
                {
                    temp[0] = nums[st];
                    temp[1] = *mid;
                    temp[2] = nums[ed];
                    res.push_back(temp);
                }
                while((ed - st) >= 1 && nums[ed] == nums[ed - 1])
                {
                    --ed;
                }
                --ed;
            }
            while((ed - st) >= 1 && nums[st] == nums[st + 1])
            {
                ++st;
            }
            ++st;
            ed = size - 1;
        }
    }
    return res;
}
版本2:运用迭代器,进行搜索
vector<vector<int>> threeSum(vector<int>& nums)
{
    vector<vector<int>> res;
    if(nums.size() < 3)
    {
        return res;
    }
    sort(nums.begin(), nums.end());
    auto p = nums.begin();
    auto q = nums.begin() + 1;
    for(; p < nums.end() - 1;)
    {
        while(q != nums.end())
        {
            int toFind = -(*p + *q);
            auto pos = find(q + 1, nums.end(), toFind);
            if(pos != nums.end())
            {
                res.push_back({ *p, toFind, *q });
            }
            if(toFind < 0)
            {
                break;
            }
            else
            {
                auto pre_q = q + 1;
                while(pre_q != nums.end() && (*pre_q == *q))
                {
                    ++pre_q;
                }
                q = pre_q;
            }
        }
        auto pre_p = p + 1;
        while(pre_p < (nums.end() - 1) && (*pre_p == *p))
        {
            ++pre_p;
        }
        p = pre_p;
        q = p + 1;
    }
    return res;
}
版本3:使用Two-pointer tech,但是无法通过所有的cases
vector<vector<int>> threeSum(vector<int>& nums)
{
    vector<vector<int>> res;
    if(nums.size() < 3)
    {
        return res;
    }
    sort(nums.begin(), nums.end());
    auto p = nums.begin();
    auto q = nums.end() - 1;
    while(p < q)
    {
        int toFind = -(*p + *q);
        auto pos = find(p + 1, q, toFind);
        if(pos != q)
        {
            res.push_back({ *p, toFind, *q });
        }
        if(toFind < 0)
        {
            auto pre_q = q - 1;
            while(pre_q != p && (*pre_q == *q))
            {
                --pre_q;
            }
            q = pre_q;
        }
//对于toFind==0情况,讨论不足。
        else
        {
            auto pre_p = p + 1;
            while(pre_p != q && (*pre_p == *p))
            {
                ++pre_p;
            }
            p = pre_p;
        }
    }
    return res;
}
错误用例

Input:[-2,0,1,1,2]

Output:[[-2,0,2]]

Expected:[[-2,0,2],[-2,1,1]]

2、别人的程序
使用Two-pointers tech,可以通过。
vector<vector<int> > threeSum(vector<int> &num)
{
    vector<vector<int> > res;
    std::sort(num.begin(), num.end());
    for(int i = 0; i < num.size(); i++)
    {
        int target = -num[i];
        int front = i + 1;
        int back = num.size() - 1;
        while(front < back)
        {
            int sum = num[front] + num[back];
            // Finding answer which start from number num[i]
            if(sum < target)
                front++;
            else if(sum > target)
                back--;
            else
            {
                vector<int> triplet(3, 0);
                triplet[0] = num[i];
                triplet[1] = num[front];
                triplet[2] = num[back];
                res.push_back(triplet);
                // Processing duplicates of Number 2
                // Rolling the front pointer to the next different number forwards
                while(front < back && num[front] == triplet[1]) front++;
                // Processing duplicates of Number 3
                // Rolling the back pointer to the next different number backwards
                while(front < back && num[back] == triplet[2]) rear--;
            }
        }
        // Processing duplicates of Number 1
        while(i + 1 < num.size() && num[i + 1] == num[i])
            i++;
    }
    return res;
}
比较简短版的
vector<vector<int>> threeSum(vector<int>& nums)
{
    vector<vector<int>> triples;
    triples.reserve(200);
    sort(nums.begin(), nums.end());
    int i = 0, last = nums.size() - 1;
    while(i < last)
    {
        int a = nums[i], j = i + 1, k = last;
        while(j < k)
        {
            int b = nums[j], c = nums[k], sum = a + b + c;
            if(sum == 0) triples.push_back({ a, b, c });
            if(sum <= 0) while(nums[j] == b && j < k) j++;
            if(sum >= 0) while(nums[k] == c && j < k) k--;
        }
        while(nums[i] == a && i < last) i++;
    }
    return triples;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值