破解三数之和:双指针高效解法

在算法题中,"三数之和" 是经典的数组类题目,属于 "两数之和" 的进阶版本,同时涉及去重这一关键细节。本文会拆解这道题的解题思路,并给出完整的 C++ 实现代码。

一、题目分析

给定整数数组nums,找出所有满足nums[i]+nums[j]+nums[k]=0i/j/k互不相等的三元组,结果不能包含重复的三元组

  • 核心难点:
    1. 如何高效枚举三元组(避免暴力 O (n³) 的时间复杂度);
    2. 如何去除重复的三元组(例如[-1,0,1][0,-1,1]属于重复结果)。

二、解题思路:排序 + 双指针

1. 预处理:排序数组

先对数组排序,好处有两个:

  • 方便后续用双指针缩小查找范围;
  • 便于去重(相同元素会相邻,可跳过重复项)。

2. 枚举 + 双指针查找

固定一个数nums[i],然后在i右侧的区间内,用左指针left=i+1、右指针right=n-1 寻找满足nums[left]+nums[right] = -nums[i]的组合:

  • nums[left]+nums[right] < -nums[i]:左指针右移(增大和);
  • nums[left]+nums[right] > -nums[i]:右指针左移(减小和);
  • 若相等:记录该三元组,同时跳过左右指针的重复元素(避免重复结果)。

3. 去重细节

  • 固定nums[i]时,若nums[i] == nums[i-1],直接跳过(避免重复枚举同一个基准数);
  • 找到有效三元组后,左指针需跳过所有与nums[left]相等的元素,右指针同理。

三、完整 C++ 代码实现

cpp

复制代码
#include <vector>
#include <algorithm>
using namespace std;

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end()); // 排序
        int n = nums.size();
        
        for (int i = 0; i < n; ++i) {
            // 基准数去重
            if (i > 0 && nums[i] == nums[i-1]) {
                continue;
            }
            int target = -nums[i];
            int left = i + 1;
            int right = n - 1;
            
            while (left < right) {
                int sum = nums[left] + nums[right];
                if (sum == target) {
                    // 记录有效三元组
                    result.push_back({nums[i], nums[left], nums[right]});
                    // 左指针去重
                    while (left < right && nums[left] == nums[left+1]) {
                        left++;
                    }
                    // 右指针去重
                    while (left < right && nums[right] == nums[right-1]) {
                        right--;
                    }
                    // 移动指针继续查找
                    left++;
                    right--;
                } else if (sum < target) {
                    left++;
                } else {
                    right--;
                }
            }
        }
        return result;
    }
};

四、复杂度分析

  • 时间复杂度:O (n²)(排序 O (nlogn) + 枚举基准数 O (n) * 双指针遍历 O (n));
  • 空间复杂度:O (logn)(排序所需的栈空间,若不考虑结果存储)。
相关推荐
busideyang4 小时前
为什么推挽输出不能接收串口数据,而准双向口可以?
c语言·stm32·单片机·嵌入式硬件·嵌入式
炸膛坦客4 小时前
单片机/C/C++八股:(二十)指针常量和常量指针
c语言·开发语言·c++
爱编码的小八嘎4 小时前
C语言完美演绎4-8
c语言
智者知已应修善业4 小时前
【proteus中lm339电压滞回比较器达到三角波转换成方波】2023-4-13
驱动开发·经验分享·笔记·硬件架构·proteus·硬件工程
I_LPL4 小时前
hot100贪心专题
数据结构·算法·leetcode·贪心
颜酱5 小时前
DFS 岛屿系列题全解析
javascript·后端·算法
WolfGang0073215 小时前
代码随想录算法训练营 Day16 | 二叉树 part06
算法
炸膛坦客5 小时前
单片机/C/C++八股:(十九)栈和堆的区别?
c语言·开发语言·c++
2401_831824966 小时前
代码性能剖析工具
开发语言·c++·算法
是wzoi的一名用户啊~6 小时前
【C++小游戏】2048
开发语言·c++