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

双指针算法进阶:三角形计数与多数求和

双指针算法利用有序数组的单调性,通过左右指针的移动高效解决查找与组合问题。涵盖有效三角形个数、两数之和、三数之和及四数之和四个经典场景。核心在于排序预处理、指针边界控制及重复元素去重。相比暴力枚举,该方法显著降低时间复杂度,是面试高频考点。

利刃发布于 2026/3/21更新于 2026/10/879 浏览
双指针算法进阶:三角形计数与多数求和

双指针算法实战

双指针是处理有序数组问题的利器。通过利用数据的单调性,我们可以将原本需要 O(n²) 甚至 O(n³) 的暴力解法优化到 O(n) 或 O(n²)。本文将结合四个经典例题,深入讲解双指针在不同场景下的应用技巧。

【611.有效三角形个数】

题目描述

给定一个包含非负整数的数组,统计其中能构成三角形的三元组个数。

核心思路

构成三角形的条件是任意两边之和大于第三边。对于排序后的数组,若固定最长边 c,只需满足 a + b > c 即可(其中 a, b 为较短两边)。因此,我们可以先对数组升序排序,然后从右向左遍历,将当前元素视为最长边,利用双指针在左侧寻找满足条件的组合。

实现细节

  1. 排序:首先将数组按升序排列。
  2. 固定最大边:从倒数第三个元素开始向前遍历,设当前索引为 i。
  3. 双指针查找:左指针 left 指向起始位置,右指针 right 指向 i-1。
    • 若 nums[left] + nums[right] > nums[i],说明 left 到 right-1 之间的所有元素与 right 都能与 nums[i] 构成三角形,数量为 right - left。随后 right-- 继续尝试更小的最长边。
    • 若和小于等于 nums[i],则需增大较短边,即 left++。
  4. 去重与边界:注意 right >= left 时停止循环,且 i 至少为 2。

文章配图 文章配图

代码实现

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--;                             // 寻找其他可能结果
                } else {
                    left++; // 寻找与最长边相加可能大于第三边的最短边
                }
            }
        }
        return count;
    }
};

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

题目描述

在一个已排序的数组中,找到两个数,使它们的和等于目标值。

核心思路

这是最经典的双指针应用场景。由于数组已有序,我们不需要像哈希表那样存储中间状态。直接让左指针指向最小值,右指针指向最大值,根据当前和与目标值的大小关系移动指针。

实现细节

  • 和小于目标值:左指针右移 (left++),以增大总和。
  • 和大于目标值:右指针左移 (right--),以减小总和。
  • 相等:找到答案,返回结果。

代码实现

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.三数之和】

题目描述

找出数组中所有和为 0 且不重复的三元组。

核心思路

将问题转化为两数之和。固定一个数 nums[i] 作为第一个数,问题就变成了在剩余部分找两个数之和为 -nums[i]。同样使用双指针求解。

实现细节

  1. 排序:必须排序以便去重和双指针操作。
  2. 固定首元素:遍历数组,将 nums[i] 设为基准。若 nums[i] > 0,后续不可能有解,可直接结束。
  3. 双指针搜索:left = i + 1, right = n - 1。
  4. 去重策略:
    • 当找到一组解后,跳过所有相同的 left 和 right 值。
    • 在固定 nums[i] 时,若 nums[i] == nums[i-1],则跳过,避免重复计算。

文章配图 文章配图

代码实现

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 - 2; ) {
            int target = nums[i];
            // 剪枝:如果当前数大于 0,后面不可能和为 0
            if (target > 0) break;
            
            int left = i + 1, right = n - 1;
            while (left < right) {
                long sum = (long)nums[left] + nums[right];
                if (sum < -target) {
                    left++;
                } else if (sum > -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 < n - 2 && nums[i] == nums[i - 1]) i++;
        }
        return ret;
    }
};

【18.四数之和】

题目描述

找出数组中所有和为 target 的不重复四元组。

核心思路

在三数之和的基础上再嵌套一层循环。固定前两个数,将问题转化为两数之和;或者固定一个数,转化为三数之和。这里采用固定一个数,调用三数之和逻辑的方式。

实现细节

  1. 排序:同上。
  2. 双重固定:外层循环固定第一个数 nums[i],内层逻辑复用三数之和的思路(固定第二个数,双指针找后两个)。
  3. 溢出处理:求和时使用 long 类型防止整数溢出。
  4. 去重:每一层循环都要跳过重复元素。

文章配图

代码实现

class Solution {
public:
    // 辅助函数:在 pos 之后找三个数和为 target_val
    vector<vector<int>> threeSumHelper(vector<int>& nums, int pos, int target_val) {
        vector<vector<int>> ret;
        int n = nums.size();
        for (int i = pos + 1; i < n - 1; ) {
            long target = (long)nums[i] - (long)target_val;
            int left = i + 1, right = n - 1;
            while (left < right) {
                long sum = (long)nums[left] + nums[right];
                if (sum < -target) {
                    left++;
                } else if (sum > -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 < n - 1 && 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();
        
        for (int i = 0; i < n - 3; ) {
            auto subRet = threeSumHelper(nums, i, target - nums[i]);
            if (!subRet.empty()) {
                for (auto& e : subRet) {
                    e.push_back(nums[i]);
                    result.push_back(e);
                }
            }
            i++;
            while (i < n - 3 && nums[i] == nums[i - 1]) i++;
        }
        return result;
    }
};

目录

  1. 双指针算法实战
  2. 【611.有效三角形个数】
  3. 题目描述
  4. 核心思路
  5. 实现细节
  6. 代码实现
  7. 【179.查找总价格为目标值的两个商品】
  8. 题目描述
  9. 核心思路
  10. 实现细节
  11. 代码实现
  12. 【15.三数之和】
  13. 题目描述
  14. 核心思路
  15. 实现细节
  16. 代码实现
  17. 【18.四数之和】
  18. 题目描述
  19. 核心思路
  20. 实现细节
  21. 代码实现

更多推荐文章

查看全部
  • AI 创作者的多维价值与深远影响分析
  • 大语言模型 (LLM) 产品开发流程参考
  • Python+AI 学习路线:从入门到实战专家
  • Ratel 斗地主服务器搭建与 cpolar 内网穿透配置
  • Git 快速入门指南:从基础概念到分支管理
  • Kotlin 类、对象和接口:定义类继承结构
  • ToDesk 顺网云海马云部署 DeepSeek 大模型对比评测
  • 文心一言:百度 AI 战略核心与国产大模型实战指南
  • Linux 进程通信:System V 共享内存原理与 C++ 封装实战
  • Python 启动器 py.exe 功能与使用指南
  • 前缀和算法实战:连续数组与矩阵区域和
  • 自然语言处理在金融风控中的实战应用
  • Spring Web MVC 入门:从概念到实践
  • OpenAI 指控 DeepSeek 模型蒸馏,字节发布 Seedance 2.0 与 Java 26 现状
  • SQL Server 2000 企业管理器打开空白故障修复方案
  • Test-Agent:开源软件测试智能助手
  • 若依 (RuoYi) 低代码框架全面分析
  • 飞书机器人对接 Claude Code 实现手机指令自动化处理
  • 默认安全治理实践:水平越权检测与前端安全防控
  • 基于大语言模型搭建私有化知识库

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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