四数之和_优选算法(C++)双指针法总结

网页直达:

https://leetcode.cn/problems/4sum

题目分析:

1.在数组里面选四个不重复的数求和==target.

2.其实算法就是和上一题的三数之和一样的.同样的要找到全部结果,需要去重.注意越界情况.

解法一:排序+暴力枚举+利用set去重.

效率低下,就不实现了

解法二:排序+双指针

1.依次固定一个数a

2.在a后面的区间内利用"三数之和"找到三个数,使这三个数等于target-a即可,而"三数之和"过程就是依次固定一个数b;在b后面的区间内,利用"双指针"找到两个数,使这两个数的和等于target-a-b即可.

细节同样是:

1.不重复

2.不遗漏

3.图像过程非常重要.

我们简单用图像说明几个过程和细节

去重:

双指针去重:

i去重:

j去重:

特殊越界:

代码实现:

无详解:

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();
        if(n<4)return ret;
        for(int i=0;i<n-3;i++)
        {
            // i的去重:只有i>0时才需要和前一个元素比较
            if(i > 0 &&nums[i]==nums[i-1])
            {
                continue;
            }
            for(int j=i+1;j<n-2;j++)
            {
                // j的去重:j必须大于i+1时才需要和前一个元素比较
                if(j > i + 1&&nums[j]==nums[j-1])
                {
                    continue;
                }
                long long sum=0;
                int left=j+1,right=n-1;
                while(left<right)
                {
                    sum=(long long)nums[i]+nums[j]+nums[left]+nums[right];//防止正整数溢出
                    if(sum>target)
                    {
                        right--;
                    }
                    else if(sum<target)
                    {
                        left++;
                    }
                    else{
                        ret.push_back({nums[i],nums[j],nums[left],nums[right]});
                        while(left < right &&nums[left]==nums[left+1])
                        {
                            left++;
                        }
                        while(left < right &&nums[right]==nums[right-1])
                        {
                            right--;
                        }
                        left++;
                        right--;
                    }
                }
            }
        }
        return ret;
    }
};

详解:

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();
        if(n<4)return ret;//一定要能构成四元组
        for(int i=0;i<n-3;i++)//确定第一个数i
        {
            // i的去重:只有i>0时才需要和前一个元素比较
            if(i > 0 &&nums[i]==nums[i-1])//i去重
            {
                continue;
            }
            for(int j=i+1;j<n-2;j++)//确定第二个数j
            {
                // j的去重:j必须大于i+1时才需要和前一个元素比较
                if(j > i + 1&&nums[j]==nums[j-1])//j去重
                {
                    continue;
                }
                long long sum=0;//大树防止溢出
                int left=j+1,right=n-1;//双指针确定其余两个数
                while(left<right)//双指针遍历
                {
                    sum=(long long)nums[i]+nums[j]+nums[left]+nums[right];//强转防止正整数溢出,其实有优化方法,但是收效甚微,就不再赘述.
                    if(sum>target)
                    {
                        right--;
                    }
                    else if(sum<target)
                    {
                        left++;
                    }
                    else{
                        ret.push_back({nums[i],nums[j],nums[left],nums[right]});//语法
                        while(left < right &&nums[left]==nums[left+1])//左指针去重
                        {
                            left++;
                        }
                        while(left < right &&nums[right]==nums[right-1])//右指针去重
                        {
                            right--;
                        }
                        left++;//寻找下一组成立的
                        right--;
                    }
                }
            }
        }
        return ret;
    }
};

双指针法总结:

到这里我们双指针算法的基本用法已经介绍的差不多了.我们来做一些总结.

双指针法是一种高效的算法技巧,通过使用两个指针在数组或链表等数据结构上移动来解决问题,通常能将时间复杂度从 O (n²) 优化到 O (n) 或 O (n log n)。以下是双指针法的系统总结:

一、核心思想

  • 利用两个指针在数据结构中移动,避免嵌套循环
  • 通过指针的有序移动(同向或反向)减少不必要的计算
  • 配合排序使用时,可高效处理查找、去重等场景

二、常见应用场景

  1. 两数之和 / 三数之和 / 四数之和

    • 先排序,再用左右指针从两端向中间移动
    • 左右指针根据当前和与目标值的比较调整移动方向
    • 关键在于去重处理和边界条件判断
  2. 链表相关问题

    • 快慢指针:判断链表是否有环、寻找链表中点
    • 前后指针:反转链表、删除倒数第 n 个节点
  3. 数组遍历与修改

    • 原地修改数组(如移除元素、移动零)
    • 合并两个有序数组
    • 滑动窗口问题(一种特殊的双指针)下一节就是滑动窗口问题.
  4. 字符串问题

    • 反转字符串
    • 判断回文串
    • 最长回文子串

三、双指针类型

  1. 同向双指针

    • 两个指针朝同一方向移动
    • 快指针先行,慢指针滞后
    • 应用:链表操作、滑动窗口、移除重复元素
  2. 反向双指针

    • 两个指针从两端向中间移动
    • 通常用于已排序的数组
    • 应用:n 数之和问题、反转操作
  3. 快慢双指针

    • 两个指针移动速度不同
    • 快指针每次移动多步,慢指针每次移动一步
    • 应用:链表环检测、寻找链表中点

四、典型代码框架

注意事项

双指针法是解决数组和链表相关问题的利器,掌握其核心思想和常见应用场景,能有效提升算法解题能力。实际应用中需根据具体问题选择合适的双指针类型和移动策略。

  1. 反向双指针(n 数之和):
cpp 复制代码
sort(arr.begin(), arr.end());
int left = 0, right = arr.size() - 1;
while (left < right) {
    int sum = arr[left] + arr[right];
    if (sum == target) {
        // 找到解
        left++;
        right--;
    } else if (sum < target) {
        left++;
    } else {
        right--;
    }
}
  1. 同向双指针(移除元素):
cpp 复制代码
int slow = 0;
for (int fast = 0; fast < nums.size(); fast++) {
    if (nums[fast] != val) {
        nums[slow] = nums[fast];
        slow++;
    }
}
  1. 快慢指针(链表中点):
cpp 复制代码
ListNode* slow = head;
ListNode* fast = head;
while (fast != nullptr && fast->next != nullptr) {
    slow = slow->next;
    fast = fast->next->next;
}
// slow指向链表中点

五、优势与注意事项

优势
7. 降低时间复杂度,提高效率
8. 空间复杂度通常为 O (1),不需要额外空间
9. 很多情况下需要先排序(如 n 数之和问题)
10. 注意边界条件,避免数组越界
11. 处理去重问题时要仔细设计判断条件
12. 指针移动的逻辑要清晰明确

双指针法是解决数组和链表相关问题的利器,掌握其核心思想和常见应用场景,能有效提升算法解题能力。实际应用中需根据具体问题选择合适的双指针类型和移动策略。

相关推荐
blank@l2 小时前
Python类和对象----实例属性,类属性(这是我理解类和对象最透彻的一次!!)
开发语言·python·python接口自动化基础·python类和对象·python实例属性·python类属性·类属性和实例属性的区别
超奇电子2 小时前
高斯包络调制正弦波的Python代码
开发语言·python
合作小小程序员小小店2 小时前
桌面预测类开发,桌面%雷达,信号预测%系统开发,基于python,tk,scikit-learn机器学习算法实现,桌面预支持向量机分类算法,CSV无数据库
python·算法·机器学习·支持向量机·scikit-learn
CAir22 小时前
CGO 原理
c++·go·cgo
java1234_小锋2 小时前
Scikit-learn Python机器学习 - 聚类分析算法 - Agglomerative Clustering(凝聚层次聚类)
python·算法·机器学习
Siren_dream2 小时前
python进阶_Day2
开发语言·python
珹洺2 小时前
Java-Spring入门指南(十二)SpringAop的三种实现方式
java·开发语言·spring
做运维的阿瑞2 小时前
使用 Python 打造一个轻量级系统信息查看器
开发语言·后端·python·系统架构
nbsaas-boot3 小时前
使用 DuckDB 构建高性能 OLAP 分析平台
java·服务器·数据库