LeetCode Hot100【双指针-15. 三数之和】

[复制链接]
发表于 2025-6-1 02:35:28 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
题目:15. 三数之和

  1. class Solution {
  2. public:
  3.     vector<vector<int>> threeSum(vector<int>& nums) {
  4.         vector<vector<int>> result;  // 存储符合条件的三元组
  5.         sort(nums.begin(), nums.end());
  6.   // 先排序
  7.         for (int i = 0; i < nums.size(); ++i) {
  8.             if (nums[i] > 0) {
  9.                 return result;  // 因为已排序,nums[i] > 0 时,后续不可能再有和为 0 的三元组
  10.             }
  11.             if (i > 0 && nums[i] == nums[i - 1]) {
  12.                 continue;  // 跳过重复元素,避免结果重复
  13.             }
  14.             
  15.             int left = i + 1;
  16.             int right = nums.size() - 1;
  17.             while (right > left) {
  18.                 int sum = nums[i] + nums[left] + nums[right];
  19.                 if (sum > 0) {
  20.                     --right;  // 如果和大于 0,说明 `right` 过大,右指针左移
  21.                 }
  22.                 else if (sum < 0) {
  23.                     ++left;  // 如果和小于 0,说明 `left` 过小,左指针右移
  24.                 }
  25.                 else {
  26.                     result.push_back(vector<int>{nums[i], nums[left], nums[right]});  // 记录有效的三元组
  27.                     // 跳过重复 `right`
  28.                     while (right > left && nums[right] == nums[right - 1]) {
  29.                         --right;
  30.                     }
  31.                     // 跳过重复 `left`
  32.                     while (right > left && nums[left] == nums[left + 1]) {
  33.                         ++left;
  34.                     }
  35.                     --right;
  36.                     ++left;
  37.                 }
  38.             }
  39.         }
  40.         return result;
  41.     }
  42. };
复制代码
执行流程

  1. nums = {-1, 0, 1, 2, -1, -4};
复制代码
排序后
  1. 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, -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
  1. vector<vector<int>> threeSum(vector<int>& nums) {
  2.     unordered_set<int> seen;
  3.     sort(nums.begin(), nums.end());
  4.     vector<vector<int>> result;
  5.     for (int i = 0; i < nums.size(); ++i) {
  6.         if (seen.count(nums[i])) continue;
  7.         seen.insert(nums[i]);
  8.         int left = i + 1, right = nums.size() - 1;
  9.         while (left < right) {
  10.             int sum = nums[i] + nums[left] + nums[right];
  11.             if (sum == 0) {
  12.                 result.push_back({nums[i], nums[left], nums[right]});
  13.                 while (left < right && nums[left] == nums[left + 1]) ++left;
  14.                 while (left < right && nums[right] == nums[right - 1]) --right;
  15.                 ++left; --right;
  16.             } else if (sum < 0) {
  17.                 ++left;
  18.             } else {
  19.                 --right;
  20.             }
  21.         }
  22.     }
  23.     return result;
  24. }
复制代码
unordered_set 进一步减少重复盘算。

基础知识

1. sort(nums.begin(), nums.end())

  1. sort(nums.begin(), nums.end());
复制代码


  • 排序 nums,确保双指针法正确执行。
  • O(n log n) 复杂度。
2. 跳过重复元素

  1. if (i > 0 && nums[i] == nums[i - 1]) {
  2.     continue;
  3. }
复制代码


  • 避免重复盘算,保证效果唯一性。
3. 双指针 left & right

  1. int left = i + 1, right = nums.size() - 1;
复制代码


  • 固定 nums,双指针 left 和 right 查找剩余两个数。
4. 盘算三数之和

  1. int sum = nums[i] + nums[left] + nums[right];
复制代码


  • 如果 sum > 0,阐明 right 过大,right–。
  • 如果 sum < 0,阐明 left 过小,left++。
  • 如果 sum == 0,存入效果,并移动 left 和 right。
5. 跳过重复 left 和 right

  1. while (right > left && nums[right] == nums[right - 1]) {
  2.     --right;
  3. }
  4. while (right > left && nums[left] == nums[left + 1]) {
  5.     ++left;
  6. }
复制代码


  • 跳过相同的 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++;跳过重复元素
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表