【算法】排序+双指针——leetcode三数之和、四数之和


三数之和

(1)排序+双指针

**  算法思路:** 和之前的两数之和类似,我们对暴力枚举进行了一些优化,利用了排序+双指针的思路:

**  我们先排序,然后固定⼀个数 a ,接着我们就可以在这个数后面的区间内,使用之前两数之和使用的算法,快速找到两个数之和和固定的a等于target即可。**

  但是要注意,为了避免其中有重复的解:

**  我们需要在找到⼀个结果之后, left 和 right 指针要跳过重复的元素;同时在使用完一次双指针算法之后,固定的 a 也要跳过重复的元素。**

**  算法实现过程:**

  给定一个包含n个整数的数组nums,函数返回所有不重复的三元组a, b, c,使得a + b + c = 0。函数首先对数组进行排序,然后使用双指针的方法来遍历数组。外层循环通过变量i遍历数组,内层循环通过变量left和right来找到满足条件的三元组。

  如果三数之和小于0,则将left右移一位;如果大于0,则将right左移一位;如果等于0,则将三个数加入结果数组ret,并继续移动left和right直到找到不重复的三元组。最后,返回结果数组ret。

cpp 复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(),nums.end());//排序
        vector<vector<int>> ret;//定义一个二维数组
        int n=nums.size();
        for(int i=0;i<n;)
        {
            int left=i+1;
            int right=n-1;
            if(nums[i]>0) break;//如果最小值大于0,那结果一定大于0
            while(left<right)
            {
                int sum=nums[i]+nums[left]+nums[right];
                if(sum<0) left++;//三数之和小于0,left++
                else if(sum>0) right--;//三数之和大于0,right--
                else 
                {
                    ret.push_back({nums[i],nums[left],nums[right]});
                    left++;//找到了一组解后,left和right都要改变
                    right--;//避免重复的解
                    while(left<right&&nums[left]==nums[left-1]) left++;
                    while(left<right&&nums[right]==nums[right+1]) right--;
                }//跳过相同的值,也是为了避免重复的解
            }
            i++;//i也要跳过相同的值,而且i不可以越界,所以要i<n
            while(i<n&&nums[i]==nums[i-1]) i++;
        }
        return ret;
    }
};

时间复杂度:O(n2)

                            

四数之和

(1)排序+双指针

**  实现方式和三数之和类似,固定两个数即可。**

cpp 复制代码
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> ret;//定义一个二维数组
        sort(nums.begin(),nums.end());//排序
        int n=nums.size();
        for(int i=0;i<n;)//固定第一个数
        {
            for(int j=i+1;j<n;)//固定第二个数
            {
                int left=j+1;
                int right=n-1;//后面的测试用例比较大,用long long
                long long aim=(long long)target-nums[i]-nums[j];
                while(left<right)
                {
                    int sum=nums[left]+nums[right];
                    if(sum>aim) right--;//如果四数之和大于目标值,right--
                    else if(sum<aim) left++;//如果四数之和小于目标值,left++
                    else 
                    {
                        ret.push_back({nums[i],nums[j],nums[left],nums[right]});
                        left++;//left++,right--,避免有重复的情况
                        right--;//跳过相同的数
                        while(left<right&&nums[left]==nums[left-1]) left++;
                        while(left<right&&nums[right]==nums[right+1]) right--;
                    }
                }
                j++;//跳过和第二个数相同的数
                while(j<n&&nums[j]==nums[j-1]) j++;
            }
            i++;//跳过和第一个数相同的数
            while(i<n&&nums[i]==nums[i-1]) i++;
        }
        return ret;
    }
};

时间复杂度:O(N3)

                            

相关推荐
sheeta19983 分钟前
LeetCode 补拙笔记 日期:2026.06.07 题目:128. 最长连续序列
笔记·算法·leetcode
sheeta199832 分钟前
LeetCode 补拙笔记 日期:2026.06.07 题目:1. 两数之和
笔记·算法·leetcode
柒和远方1 小时前
LeetCode 452. 用最少数量的箭引爆气球 —— 区间贪心经典:排序 + 扫描一箭穿心
javascript·python·算法
Zhang~Ling3 小时前
C++ 红黑树封装:myset和mymap的底层实现
开发语言·数据结构·c++·算法
ECT-OS-JiuHuaShan3 小时前
什么是对和错?——“有针对性定义域的逻辑值的真伪”:认识论终极追问的公理化裁决
数据库·人工智能·算法·机器学习·数学建模
Merlyn103 小时前
【栈】155. 最小栈
python·算法
一个不知名程序员www3 小时前
算法学习入门---算法题DAY5
c++·算法
San813_LDD3 小时前
[量化]《虚函数调用时间复杂度完全解析:为什么是 O(1) 以及它的真实代价》
java·数据结构·算法
MartinYeung53 小时前
[论文学习]利用索引梯度优化基于优化的 LLM 越狱攻击:MAGIC 方法的深度分析与实现
人工智能·学习·算法
数据仓库搬砖人3 小时前
特征选择三剑客:前向、后向、全子集,哪种更适合你?
算法