马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
题目:15. 三数之和
- class Solution {
- public:
- vector<vector<int>> threeSum(vector<int>& nums) {
- vector<vector<int>> result; // 存储符合条件的三元组
- sort(nums.begin(), nums.end());
- // 先排序
- for (int i = 0; i < nums.size(); ++i) {
- if (nums[i] > 0) {
- return result; // 因为已排序,nums[i] > 0 时,后续不可能再有和为 0 的三元组
- }
- if (i > 0 && nums[i] == nums[i - 1]) {
- continue; // 跳过重复元素,避免结果重复
- }
-
- int left = i + 1;
- int right = nums.size() - 1;
- while (right > left) {
- int sum = nums[i] + nums[left] + nums[right];
- if (sum > 0) {
- --right; // 如果和大于 0,说明 `right` 过大,右指针左移
- }
- else if (sum < 0) {
- ++left; // 如果和小于 0,说明 `left` 过小,左指针右移
- }
- else {
- result.push_back(vector<int>{nums[i], nums[left], nums[right]}); // 记录有效的三元组
- // 跳过重复 `right`
- while (right > left && nums[right] == nums[right - 1]) {
- --right;
- }
- // 跳过重复 `left`
- while (right > left && nums[left] == nums[left + 1]) {
- ++left;
- }
- --right;
- ++left;
- }
- }
- }
- return result;
- }
- };
复制代码 执行流程
- nums = {-1, 0, 1, 2, -1, -4};
复制代码 排序后
- nums = {-4, -1, -1, 0, 1, 2}
复制代码 执行步骤如下:
i (固定数)leftright三元组是否记载-4 (i = 0)-1 (1)2 (5)-4 + (-1) + 2 = -3❌-4 (i = 0)0 (3)2 (5)-4 + 0 + 2 = -2❌-4 (i = 0)1 (4)2 (5)-4 + 1 + 2 = -1❌-1 (i = 1)-1 (2)2 (5)-1 + (-1) + 2 = 0✅ 记载 {-1, -1, 2}-1 (i = 1)0 (3)1 (4)-1 + 0 + 1 = 0✅ 记载 {-1, 0, 1}0 (i = 3)1 (4)2 (5)0 + 1 + 2 = 3❌ 最终返回
- {{-1, -1, 2}, {-1, 0, 1}}
复制代码 时间 & 空间复杂度
操纵时间复杂度空间复杂度排序 numsO(nlogn)O(1)遍历 numsO(n)O(1)双指针 left & rightO(n)O(1) 最终
- 时间复杂度:O(n2)(排序 + 双指针)
- 空间复杂度:O(1)(效果 vector 不计入额外空间)
优化 & 变种
利用 unordered_set 存储已遍历的 nums
- vector<vector<int>> threeSum(vector<int>& nums) {
- unordered_set<int> seen;
- sort(nums.begin(), nums.end());
- vector<vector<int>> result;
- for (int i = 0; i < nums.size(); ++i) {
- if (seen.count(nums[i])) continue;
- seen.insert(nums[i]);
- int left = i + 1, right = nums.size() - 1;
- while (left < right) {
- int sum = nums[i] + nums[left] + nums[right];
- if (sum == 0) {
- 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 < 0) {
- ++left;
- } else {
- --right;
- }
- }
- }
- return result;
- }
复制代码 unordered_set 进一步减少重复盘算。
基础知识
1. sort(nums.begin(), nums.end())
- sort(nums.begin(), nums.end());
复制代码
- 排序 nums,确保双指针法正确执行。
- O(n log n) 复杂度。
2. 跳过重复元素
- if (i > 0 && nums[i] == nums[i - 1]) {
- continue;
- }
复制代码
3. 双指针 left & right
- int left = i + 1, right = nums.size() - 1;
复制代码
- 固定 nums,双指针 left 和 right 查找剩余两个数。
4. 盘算三数之和
- int sum = nums[i] + nums[left] + nums[right];
复制代码
- 如果 sum > 0,阐明 right 过大,right–。
- 如果 sum < 0,阐明 left 过小,left++。
- 如果 sum == 0,存入效果,并移动 left 和 right。
5. 跳过重复 left 和 right
- while (right > left && nums[right] == nums[right - 1]) {
- --right;
- }
- while (right > left && nums[left] == nums[left + 1]) {
- ++left;
- }
复制代码
- 跳过相同的 left 和 right,避免效果重复。
总结
C++语法作用sort(nums.begin(), nums.end())先排序,确保双指针法有效if (i > 0 && nums == nums[i - 1]) continue;C++ 动态数组unordered_map<int, int>跳过重复 numswhile (left < right)双指针法if (sum == 0)记载三元组while (nums[left] == nums[left + 1]) left++;跳过重复元素 |