【Hot 100 刷题计划】 LeetCode 15. 三数之和 | C++ 排序+双指针

LeetCode 15. 三数之和

📌 题目描述

题目级别:中等

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

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

💡 破题思路:排序 + 固定一端 + 双指针夹逼

这道题如果用暴力三层 for 循环,时间复杂度是 O(N3)O(N^3)O(N3),绝对会超时。而且暴力法极难处理"不重复的三元组"这个要求。

最高效的解法是 降维打击 :把 O(N3)O(N^3)O(N3) 降为 O(N2)O(N^2)O(N2)。

核心流程如下:

  1. 先排序(极其关键)
    排序是双指针夹逼的前提,也是轻松跳过重复元素的基石。
  2. 固定第一个数 (nums[i])
    遍历数组,将 nums[i] 作为三元组中最小的那个数固定下来。此时问题就变成了:在 i 之后的数组中,寻找两个数,使它们的和等于 -nums[i](这就是经典的《两数之和 II》问题)。
  3. 双指针向中间夹逼
    设左指针 l = i + 1,右指针 r = n - 1
    • 如果 sum == 0,记录答案,并让 lr 同时向中间收缩。
    • 如果 sum < 0,说明总和太小,左指针 l 右移以增大数值。
    • 如果 sum > 0,说明总和太大,右指针 r 左移以减小数值。
  4. 地狱级细节:三重去重
    • 去重 1 (外层) :如果当前的 nums[i] 和上一个固定过的 nums[i-1] 一样,直接 continue 跳过,因为同样的开头一定会搜出同样的结果。
    • 去重 2 & 3 (内层) :当找到一组正确答案后,左指针 l 必须跳过身后所有与之重复的元素,右指针 r 也必须跳过身前所有与之重复的元素,否则三元组会重复!

💻 C++ 代码实现 (最强双指针模板)

cpp 复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n = nums.size();
        // 1. 必须先排序,为双指针夹逼和去重打下基础
        sort(nums.begin(), nums.end());

        vector<vector<int>> res;

        // 2. 遍历数组,固定第一个数 nums[i]
        for (int i = 0; i < n; i ++ )
        {
            // 去重点 1:如果固定的这个数和上一次固定的数一样,直接跳过,防止产生重复三元组
            if (i && nums[i] == nums[i - 1]) continue;
            
            // 定义左右双指针
            int l = i + 1, r = n - 1;

            // 3. 双指针开始向中间夹逼
            while (l < r)
            {
                int sum = nums[i] + nums[l] + nums[r];
                
                if (sum == 0) 
                {
                    // 找到一组符合条件的解,塞入结果集
                    res.push_back({nums[i], nums[l], nums[r]});
                    
                    // 去重点 2:左指针跳过所有重复元素
                    while (l < r && nums[l] == nums[l + 1]) l ++ ;
                    // 去重点 3:右指针跳过所有重复元素
                    while (l < r && nums[r] == nums[r - 1]) r -- ;
                    
                    // 双双往中间聚拢一步,寻找下一个潜在的组合
                    l ++ , r -- ;
                }
                // sum 太小,左指针右移找更大的数
                else if (sum < 0) l ++ ;
                // sum 太大,右指针左移找更小的数
                else r -- ;
            }
        }

        return res;
    }
};
相关推荐
汉克老师36 分钟前
GESP6级C++考试语法知识(十七、数据结构(三、认识队列 Queue))
数据结构·c++·队列·gesp6级·gesp六级·数组模拟队列
灰灰勇闯IT1 小时前
ops-reduce:ReduceMax 与 ReduceMean 的并行优化
算法
水木流年追梦1 小时前
大模型入门-Reward 奖励模型训练
开发语言·python·算法·leetcode·正则表达式
沙威玛_LHE1 小时前
P13376题解
算法
DFT计算杂谈2 小时前
KPROJ编译教程
java·前端·python·算法·conda
重生之我是Java开发战士2 小时前
【笔试强训】Week5:空调遥控, kotor和气球,走迷宫,主持人调度II,体操队形,二叉树的最大路径和,排序子序列,消减整数
java·算法·动态规划
j_xxx404_2 小时前
Linux进程信号捕捉与操作系统运行本质深度解析
linux·运维·服务器·开发语言·c++·人工智能·ai
吃好睡好便好3 小时前
用if…end…语句计算分段函数
开发语言·人工智能·学习·算法·matlab
vx-程序开发3 小时前
基于机器学习的动漫可视化系统的设计与实现-计算机毕业设计源码08339
java·c++·spring boot·python·spring·django·php
灰灰勇闯IT3 小时前
ops-memory:CANN Runtime 的 Tensor 内存管理
算法