详细思路
- 排序数组:首先对数组
nums
进行排序,目的是为了方便后续使用双指针查找和避免重复结果。 - 遍历数组:使用一个
for
循环从头遍历到倒数第三个元素。i
表示当前固定的元素。- 跳过重复元素:如果当前元素
nums[i]
与前一个元素相同,则跳过,避免重复结果。 - 提前结束循环:如果当前元素
nums[i]
大于0,因为数组已经排序,后面的元素也都大于0,不可能存在满足条件的三元组,直接结束循环。
- 跳过重复元素:如果当前元素
- 双指针查找:对于每个固定的元素
nums[i]
,使用双指针在其后的子数组中查找两个数nums[j]
和nums[k]
,使得它们的和为-nums[i]
。- 调整指针:根据当前三数之和调整双指针的位置:
- 如果和大于0,说明右边的数太大,右指针
k
左移。 - 如果和小于0,说明左边的数太小,左指针
j
右移。 - 如果和等于0,则找到一个满足条件的三元组,将其加入结果,并跳过重复的元素。
- 如果和大于0,说明右边的数太大,右指针
- 调整指针:根据当前三数之和调整双指针的位置:
- 返回结果:所有符合条件的三元组都存储在
result
中,最终返回该结果。
通过这种方法,可以在时间复杂度为 O(n^2)
的情况下找到所有不重复的满足条件的三元组。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result; // 用于存储结果三元组
int n = nums.size();
if (n <= 2)
return result; // 如果数组长度小于等于2,不可能有满足条件的三元组,直接返回空结果
sort(nums.begin(), nums.end()); // 将数组排序
// 遍历数组,每次固定一个元素
for (int i = 0; i <= n - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue; // 跳过重复的元素,以避免结果中有重复的三元组
}
if (nums[i] > 0)
break; // 如果当前固定的数大于0,由于数组已经排序,后面的数也大于0,不可能找到满足条件的三元组
int j = i + 1, k = n - 1; // 初始化双指针,一个从左边开始,一个从右边开始
while (j < k) {
int sum = nums[i] + nums[j] + nums[k];
if (sum > 0) {
k--; // 如果三数之和大于0,移动右指针向左
} else if (sum < 0) {
j++; // 如果三数之和小于0,移动左指针向右
} else {
// 找到一个满足条件的三元组
result.push_back({nums[i], nums[j], nums[k]});
// 跳过重复的元素
while (j < k && nums[j] == nums[j + 1]) j++;
while (j < k && nums[k] == nums[k - 1]) k--;
j++;
k--;
}
}
}
return result; // 返回结果
}
};