目录
1.题目描述:
给你一个整数数组 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]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0
2.算法思路:
算法思路(双指针法)
1. 排序预处理
- 目的:使数组有序,便于使用双指针技巧和去重。
- 操作:调用
sort(nums.begin(), nums.end())
,时间复杂度 O(n log n)。
2. 外层循环(固定第一个数 first
)
- 遍历范围:
first
从0
到nums.size() - 1
。 - 去重:
- 如果
nums[first] == nums[first - 1]
,跳过当前first
,避免重复解。
- 如果
- 计算目标值:
target = -nums[first]
,表示剩余两数之和需要等于target
。
3. 内层双指针(second
和 third
)
- 初始化:
second = first + 1
(左指针)。third = nums.size() - 1
(右指针)。
- 移动规则:
- 如果
nums[second] + nums[third] > target
,则third--
(右指针左移,减少和)。 - 如果
nums[second] + nums[third] < target
,则second++
(左指针右移,增加和)。 - 如果
nums[second] + nums[third] == target
,记录解,并跳过重复的second
和third
。
- 如果
- 终止条件:
- 当
second >= third
时,退出循环。
- 当
4. 去重优化
- 外层去重:跳过重复的
nums[first]
。 - 内层去重:在找到解后,跳过重复的
nums[second]
和nums[third]
。
时间复杂度分析
- 排序:
O(n log n)
。 - 外层循环:
O(n)
。- 每个
first
只遍历一次。
- 每个
- 内层双指针:
O(n)
。- 对于每个
first
,second
和third
总共最多遍历n
次(second
从左到右,third
从右到左,不会重复扫描)。
- 对于每个
- 总时间复杂度:
- O(n log n) + O(n²) = O(n²)(当
n
较大时,O(n²)
主导)。
- O(n log n) + O(n²) = O(n²)(当
3.代码展示:
vector<vector<int>> threeSum(vector<int>& nums) {
vector < vector<int>>result;
//先进行排序,方便后续的去重操作
sort(nums.begin(), nums.end());
for (int first = 0; first < nums.size(); first++) {
//跳出重复的first
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
int third = nums.size() - 1;//始终指向最后一个元素
int target = -nums[first];//用于判断,相当与second+third和target的关系
for (int second = first + 1; second < nums.size(); second++) {
//跳出重复的second
if (second > first+1 && nums[second] == nums[second - 1]) {
continue;
}
//接下来,判断三者的关系,second+third > target,则third--,直到second>third
while (second < third && nums[second] + nums[third] > target) {
//指针后移
third--;
}
//如果相等就插入
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
result.push_back({ nums[first] ,nums[second] ,nums[third] });
}
}
}
return result;
}
15. 三数之和 - 力扣(LeetCode)https://leetcode.cn/problems/3sum/description/