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

双指针算法实战:有效三角形与多数之和

双指针算法适用于有序数组的查找问题。通过排序后固定一端,利用左右指针相向移动寻找满足条件的组合。文章涵盖有效三角形个数统计、两数之和、三数之和及四数之和四个经典案例。重点讲解去重策略与边界条件处理,相比暴力枚举显著降低时间复杂度。

灵魂摆渡发布于 2026/3/21更新于 2026/7/1935 浏览
双指针算法实战:有效三角形与多数之和

1、有效三角形的个数

给定一个包含非负整数的数组 nums,返回其中可以组成三角形三条边的三元组个数。

示例 1: 输入: nums = [2,2,3,4] 输出: 3 解释: 有效的组合是: 2,3,4 (使用第一个 2), 2,3,4 (使用第二个 2), 2,2,3

示例 2: 输入: nums = [4,2,3,4] 输出: 4

解题思路:

  1. 暴力解法:枚举所有的三条边,判断它们是否可以组成三角形,记录有效三角形的个数。不过 n^3 的时间复杂度会超出时间限制!
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        int len=nums.size(),count=0;
        for(int a=0;a<len-2;a++) {
            for(int b=a+1;b<len-1;b++) {
                for(int c=b+1;c<len;c++) {
                    if(nums[a]+nums[b]>nums[c] &&nums[a]+nums[c]>nums[b] &&nums[b]+nums[c]>nums[a]) count++;
                }
            }
        }
        return count;
    }
};
  1. 更优解法:先将数组排序,因为判断三个数是否可以构成三角形只需要比较较小两边之和是否大于第三边即可。

  2. 排序后,nums[len-1]的位置就是最大值,我们先用 right_idx 固定一端,right 固定在 right_idx 左侧,left 固定在起点。

  3. 判断 nums[left]+nums[right] 是否大于 nums[right_idx]。

    • a. 如果小于,left++
    • b. 如果大于,count+=(right-left)。固定 right_idx 和 right 两边后,left 是 right 之后最小的一边。如果最小的一边加上 right 都大于 right_idx,那其后的边一定可以构成三角形。所以我们就没有必要进行无意义的枚举。
    • c. 此时固定 right_idx 和 right 的情况已近枚举完成,那我们就让 right--。
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        int right_idx=nums.size()-1,count=0;
        //排序
        sort(nums.begin(),nums.end());
        //固定枚举 right_idx
        while(right_idx>=2) {
            //固定枚举 right
            int right=right_idx-1;
            int left=0;
            while(left<right) {
                if(nums[left]+nums[right]>nums[right_idx]) {
                    count+=(right-left);
                    right--;
                } else left++;
            }
            right_idx--;
        }
        return count;
    }
};

2、查找总价值为目标值的两个商品

购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况,返回任一结果即可。

示例 1: 输入:price = [3, 9, 12, 15], target = 18 输出:[3,15] 或者 [15,3]

示例 2: 输入:price = [8, 21, 27, 34, 52, 66], target = 61 输出:[27,34] 或者 [34,27]

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 {
                return {price[left],price[right]};
            }
        }
        return {-1,-1};
    }
};

3、三数之和

给你一个整数数组 nums,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k,同时还满足 nums[i] + nums[j] + nums[k] == 0。请你返回所有和为 0 且不重复的三元组。

**注意:**答案中不可以包含重复的三元组。

示例 1: 输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]]

示例 2: 输入:nums = [0,1,1] 输出:[]

示例 3: 输入:nums = [0,0,0] 输出:[[0,0,0]]

解题思路:

  1. 这个题目的整体思路可以转化为两数之和==target,和上一道题目相似,不过在细节上还是有些不同。
  2. 排序后,我们定义 k 在 len-1 的位置,left=0,right=k-1。判断 nums[left]+nums[right]==-nums[k] 就可以了。

去重问题:

找到一个三元组后,left++,right--。

  • a. 如果 left==left-1(逻辑修正:指移动后值相同),那么我们找到的下一个三元组必然和前一个相等!(因为 left 和 k 固定了)
  • b. 同理,如果 right==right+1(逻辑修正:指移动后值相同),那么我们找到的下一个三元组必然和前一个相等!
  • c. 再有,如果 k==k+1(逻辑修正:指外层循环移动后值相同),我们在下一个区间查找的所有情况再上一个区间都查找过了!
  • d. 所以这三种情况我们都要跳过相同的元素来进行去重操作!

解题代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ret;
        sort(nums.begin(),nums.end());//排序
        int len=nums.size();
        for(int k=len-1;k>=2;) {
            if(nums[k]<0) break;//小优化
            int left=0,right=k-1;
            while(left<right) {
                if(nums[left]+nums[right]<-nums[k]) left++;
                else if(nums[left]+nums[right]>-nums[k]) right--;
                else {
                    ret.push_back({nums[left++],nums[right--],nums[k]});
                    //去重
                    while(left<right&&nums[left]==nums[left-1]) left++;
                    while(left<right&&nums[right]==nums[right+1]) right--;
                }
            }
            //去重
            k--;
            while(k>=2&&nums[k]==nums[k+1]) k--;
        }
        return ret;
    }
};

4、四数之和

给你一个由 n 个整数组成的数组 nums,和一个目标值 target。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]]:0 <= a, b, c, d < n,a、b、c 和 d 互不相同,nums[a] + nums[b] + nums[c] + nums[d] == target。

你可以按任意顺序返回答案。

示例 1: 输入:nums = [1,0,-1,0,-2,2], target = 0 输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

示例 2: 输入:nums = [2,2,2,2,2], target = 8 输出:[[2,2,2,2]]

解题思路:

  1. 这道题目的整体思路和三数之和差不多,我们可以把上一题理解为两数之和==target(0) - 一个数(自己固定枚举)。
  2. 而这道题目无非就是再三数之和的基础上,再多枚举一个数而已!

解题代码:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        int len=nums.size();
        sort(nums.begin(),nums.end());
        vector<vector<int>> ret;
        for(int d=len-1;d>=3;) {
            if(target<0&&nums[0]>=0) break;//小优化
            //三数之和逻辑
            for(int c=d-1;c>=2;) {
                long long tmp=(long long)target-nums[c]-nums[d];
                int left=0;
                int right=c-1;
                while(left<right) {
                    if(nums[left]+nums[right]<tmp) left++;
                    else if(nums[left]+nums[right]>tmp) right--;
                    else {
                        ret.push_back({nums[left++],nums[right--],nums[c],nums[d]});
                        //left,right去重
                        while(left<right&&nums[left]==nums[left-1]) left++;
                        while(left<right&&nums[right]==nums[right+1]) right--;
                    }
                }
                //c去重
                c--;
                while(c>=2&&nums[c]==nums[c+1]) c--;
            }
            //d去重
            d--;
            while(d>=3&&nums[d]==nums[d+1]) d--;
        }
        return ret;
    }
};

目录

  1. 1、有效三角形的个数
  2. 2、查找总价值为目标值的两个商品
  3. 3、三数之和
  4. 4、四数之和
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Pico 4XVR 1.10.13 安装与使用指南
  • IntelliJ IDEA 集成 GitHub Copilot 安装配置与实战技巧
  • Windows 系统 Visual C++ 运行库故障诊断与修复指南
  • Spring Boot 集成 MyBatis 实战:基础 CRUD 与核心原理
  • CosyVoice 语音大模型部署与声音克隆指南
  • AI 生成 UI 设计工具推荐及免费额度使用指南
  • LeetCode 原地复写零:双指针逆向填充 O(n) 最优解
  • 从 Webhook 到 AI Agent:钉钉周报提醒机器人演进
  • 服务器安全防护实战:从真实案例复盘入侵手段与加固策略
  • AI 零基础入门与实践完全指南
  • GitHub Copilot 接入第三方 OpenAI 兼容模型指南
  • AGI 的皇帝新衣:OpenAI 商业模式能否抵御开源模型冲击?
  • 2026 年 9 款 AI 毕业论文写作工具深度测评
  • LLM 存储优化实战:解决大量 QA 与长对话记忆问题
  • 基于 DeepSeek 与腾讯云 HAI 快速构建个人主页
  • 客观审视开源平台 BuildingAI
  • Java RESTful 接口开发实战指南
  • C++ 二叉搜索树(BST)原理与完整实现
  • 本科文献综述全流程指南:基于 AI 工具的选题到成稿写作方法
  • Flutter 三方库 objectid:离线分布式高可用 ID 引擎

相关免费在线工具

  • 加密/解密文本

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