跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

双指针算法进阶:从三角形计数到四数之和

双指针配合排序是解决数组查找问题的利器。通过有效三角形个数、两数之和、三数之和及四数之和四个经典案例,演示了如何固定一边或两边,利用左右指针在有序数组中快速定位目标组合。重点讲解了去重策略、边界条件处理以及时间复杂度优化,帮助读者掌握此类算法的核心逻辑与实战技巧。

清心发布于 2026/3/29更新于 2026/10/2691 浏览
双指针算法进阶:从三角形计数到四数之和

前言

双指针配合排序是解决数组查找问题的利器。当数据有序时,利用两个指针向中间靠拢或同向移动,往往能将暴力解法的复杂度优化一个数量级。下面通过四个经典案例,演示如何固定一边或两边,在有序数组中快速定位目标组合。

611. 有效三角形个数

核心思路

构成三角形的条件是任意两边之和大于第三边。若设三边为 a, b, c(c 为最长边),则只需满足 a + b > c。

为了高效判断,我们先将数组升序排序。排序后,单调性变得清晰:每次固定最大值作为第三边,最左侧元素作为最短边,次大值作为最长边。此时若 nums[left] + nums[right] > nums[i],由于数组有序,left 与 right 之间的所有元素与 nums[right] 相加必然大于 nums[i],因此可以直接累加 right - left 个解。

实现要点

  • 排序:升序排列,方便后续逻辑。
  • 指针移动:外层循环从右向左固定最大边 i;内层 left 指向头,right 指向 i-1。
  • 去重与边界:注意 i 至少为 2,且 left < right 时继续搜索。
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        sort(nums.begin(), nums.end()); // 升序排序
        int count = 0;
        // 从右往左依次将最大值作为第三边
        for(int i = nums.size() - 1; i >= 2; i--) {
            int left = 0;      // 左指针(最短边)
            int right = i - 1; // 右指针(最长边)
            while(left < right) {
                if(nums[left] + nums[right] > nums[i]) { // 两边之和大于第三边
                    count += right - left; 
                    right--;               
                }  {
                    left++; 
                }
            }
        }
         count;
    }
};
// 更新结果
// 寻找其他可能结果
else
// 寻找与最长边相加可能大于第三边的最短边
return

179. 查找总价格为目标值的两个商品

核心思路

这是典型的'两数之和'变体。既然题目保证数组已排序(或可排序),直接套用双指针模板即可。

  • 和小于目标值:左指针右移,增大总和。
  • 和大于目标值:右指针左移,减小总和。
  • 相等:找到答案,退出。
class Solution {
public:
    vector<int> twoSum(vector<int>& price, int target) {
        int left = 0, right = price.size() - 1;
        while(left < right) {
            if(price[left] + price[right] < target) left++;
            else if(price[left] + price[right] > target) right--;
            else break;
        }
        return {price[left], price[right]};
    }
};

15. 三数之和

核心思路

将问题转化为两数之和:固定一个数 nums[i],剩余部分寻找 target = -nums[i]。这本质上是在子数组上运行上述的双指针逻辑。

关键细节

  1. 去重:这是最容易出错的地方。如果当前数字与前一个相同,跳过;找到解后,左右指针也要跳过重复值。
  2. 剪枝优化:因为数组已排序,如果固定的数 nums[i] > 0,后续不可能有三数之和为 0,可直接结束循环。
  3. 边界检查:i 最多遍历到倒数第三个元素。
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end()); // 排序
        vector<vector<int>> ret;
        // 从左往右依次固定元素为 target
        for(int i = 0; i < nums.size() - 2;) {
            int target = nums[i];
            int left = i + 1, right = nums.size() - 1;
            
            while(left < right && target <= 0) {
                if(nums[left] + nums[right] < -target) left++;
                else if(nums[left] + nums[right] > -target) right--;
                else {
                    ret.push_back({target, nums[left], nums[right]});
                    left++, right--;
                    // 去重
                    while(left < right && nums[left] == nums[left - 1]) left++;
                    while(left < right && nums[right] == nums[right + 1]) right--;
                }
            }
            i++;
            // 去重 target
            while(i < nums.size() - 2 && nums[i] == nums[i - 1]) i++;
        }
        return ret;
    }
};

18. 四数之和

核心思路

四数之和可以看作是三数之和的扩展。先固定一个数 a,问题就转化为在剩余数组中寻找三数之和等于 target - a。代码结构上与三数之和高度相似,只是多了一层循环。

实现要点

  • 复用三数之和的逻辑,但要注意参数传递。
  • 同样需要处理去重逻辑,防止结果集重复。
  • 注意整数溢出风险,求和时建议使用 long long 类型。
class Solution {
public:
    // 找满足三数之和的数
    vector<vector<int>> threeSum(vector<int>& nums, int pos, int target_val) {
        vector<vector<int>> ret;
        int n = nums.size() - 2;
        for(int i = pos + 1; i < n;) {
            long target = (long)nums[i] - (long)target_val;
            int left = i + 1, right = nums.size() - 1;
            while(left < right) {
                if(nums[left] + nums[right] < -target) left++;
                else if(nums[left] + nums[right] > -target) right--;
                else {
                    ret.push_back({nums[i], nums[left], nums[right]});
                    left++, right--;
                    while(left < right && nums[left] == nums[left - 1]) left++;
                    while(left < right && nums[right] == nums[right + 1]) right--;
                }
            }
            i++;
            while(i < nums.size() - 2 && nums[i] == nums[i - 1]) i++;
        }
        return ret;
    }

    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> result;
        int n = nums.size() - 3;
        for(int i = 0; i < n;) {
            auto ret = threeSum(nums, i, target - nums[i]);
            if(!ret.empty()) {
                for(auto e : ret) {
                    e.push_back(nums[i]);
                    result.push_back(e);
                }
            }
            i++;
            while(i < nums.size() - 3 && nums[i] == nums[i - 1]) i++;
        }
        return result;
    }
};

目录

  1. 前言
  2. 611. 有效三角形个数
  3. 核心思路
  4. 实现要点
  5. 179. 查找总价格为目标值的两个商品
  6. 核心思路
  7. 15. 三数之和
  8. 核心思路
  9. 关键细节
  10. 18. 四数之和
  11. 核心思路
  12. 实现要点

更多推荐文章

查看全部
  • 使用 Document Picture-in-Picture API 实现视频小窗同步控制
  • Midjourney 中文版入门指南:指令优化与使用技巧
  • 2025 年 Java 与 AI 技术融合学习路线
  • 算力调度算法:基于AI的智能算力分配方法
  • 三款主流云电脑部署 DeepSeek 模型实测对比
  • GLM-4.6V-Flash-WEB AI 看图说话应用部署与实战
  • 大模型 LangChain 框架基础与使用示例
  • OpenClaw Session 机制详解:重置、压缩、剪枝与记忆管理
  • vscode copilot 的配置文件提示警告
  • 理想汽车大模型算法工程师面试复盘:RAG、加速框架与自动驾驶落地
  • 双指针算法详解:原理与经典题目实战
  • Neo4j Desktop 安装与使用指南
  • Django WebAPI 项目搭建与基础配置
  • C++ STL 双端队列 deque 与优先级队列模拟实现及仿函数详解
  • Python 版本与环境管理:虚拟环境实战指南
  • Qwen-Image-2512 本地部署与 ComfyUI 实战
  • Linux OpenEuler 环境下 Milvus 在线与离线安装卸载及连接异常处理
  • 从三年前端到 CS 硕士:我在韩国留学的得失复盘
  • C++11 左值右值引用区别与移动语义解决传值返回对象销毁问题
  • FPGA 基于 SJA1000 的 CAN 总线控制器 Verilog/VHDL 实现

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online