题源: 15. 三数之和
解题思路
-
排序:首先对数组进行排序。这样可以方便后续操作,并且可以有效地避免重复的三元组和简化三元组的查找过程。
-
外层循环:遍历排序后的数组,但只需遍历到倒数第三个元素(因为需要至少三个元素来形成三元组)。此外,如果当前元素大于0,则终止循环,因为三个正数相加不可能为0。
-
跳过重复元素:如果当前元素与前一个元素相同,则跳过此次循环,以避免重复的三元组。
-
双指针寻找:设置两个指针
l
(左指针)和r
(右指针),分别指向当前元素的下一个位置和数组的末尾。通过移动这两个指针来找出与当前元素相加为0的两个元素:- 如果三数之和为0,将这三个数作为一个三元组添加到结果中,然后移动指针,并跳过所有重复的元素。
- 如果三数之和小于0,向右移动左指针
l
,以增大总和。 - 如果三数之和大于0,向左移动右指针
r
,以减小总和。
-
结束条件:当左指针不再小于右指针时,结束内层循环。外层循环结束后,所有满足条件的三元组都已找到。
复杂度分析
- 时间复杂度:O(n^2)。数组排序需要O(n log n),双指针遍历数组大约需要O(n^2)。
- 空间复杂度:O(log n)到O(n),取决于所使用的排序算法的空间复杂度。
代码实现
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 < nums.size() - 2 && nums[i] <= 0; i++) {
if(i > 0 && nums[i] == nums[i - 1]) continue;// 跳过重复的元素
int l = i + 1;
int r = nums.size() - 1;
while(l < r){
int sum = nums[i] + nums[l] + nums[r];
if(sum == 0){
result.push_back({nums[i], nums[l], nums[r]});
while (l < r && l + 1 < nums.size() && nums[l] == nums[l + 1]) l ++;// 跳过重复的元素
while(l < r && r - 1 > 0 && nums[r] == nums[r - 1]) r --;// 跳过重复的元素
l++, r--;
}else if(sum > 0) r --;
else l ++;
}
}
return result;
}
};