在算法题中,"三数之和" 是经典的数组类题目,属于 "两数之和" 的进阶版本,同时涉及去重这一关键细节。本文会拆解这道题的解题思路,并给出完整的 C++ 实现代码。
一、题目分析
给定整数数组nums,找出所有满足nums[i]+nums[j]+nums[k]=0且i/j/k互不相等的三元组,结果不能包含重复的三元组。
- 核心难点:
- 如何高效枚举三元组(避免暴力 O (n³) 的时间复杂度);
- 如何去除重复的三元组(例如
[-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)(排序所需的栈空间,若不考虑结果存储)。