【Day 5】公开打卡第5天 | LeetCode 15. 三数之和(排序 + 双指针) + 去重技巧

7 阅读2分钟
  1. 今日打卡宣言 Day 5,把昨天漏掉的补上,。项目还是忙,但这道三数之和是面试高频题,必须搞懂,冲!

  2. LeetCode 部分

    • 题目链接:leetcode.cn/problems/3s…
    • 难度:中等
    • 时间复杂度:O(n²)(排序 O(n log n) + 双指针 O(n))
    • 核心思路(简短3行): 先排序数组 → 固定第一个数 nums[i](从左到右),然后在 i+1 ~ n-1 区间用双指针(left = i+1, right = n-1)找两数和为 -nums[i]。遇到重复元素跳过,避免重复三元组。
    • 代码(Go 版本,标准写法 + 去重):

Go

func threeSum(nums []int) [][]int {
    sort.Ints(nums)  // 先排序
    n := len(nums)
    var res [][]int
    
    for i := 0; i < n-2; i++ {
        // 去重:跳过相同的 nums[i]
        if i > 0 && nums[i] == nums[i-1] {
            continue
        }
        
        // 如果当前 nums[i] > 0,后面的和不可能为0,直接结束
        if nums[i] > 0 {
            break
        }
        
        left, right := i+1, n-1
        for left < right {
            sum := nums[i] + nums[left] + nums[right]
            if sum == 0 {
                res = append(res, []int{nums[i], nums[left], nums[right]})
                
                // 去重:跳过相同的 leftright
                for left < right && nums[left] == nums[left+1] {
                    left++
                }
                for left < right && nums[right] == nums[right-1] {
                    right--
                }
                left++
                right--
            } else if sum < 0 {
                left++
            } else {
                right--
            }
        }
    }
    return res
}
  • C++ 版本(如果你想双语放简版):

C++

vector<vector<int>> threeSum(vector<int>& nums) {
    sort(nums.begin(), nums.end());
    vector<vector<int>> res;
    int n = nums.size();
    
    for (int i = 0; i < n - 2; ++i) {
        if (i > 0 && nums[i] == nums[i-1]) continue;
        if (nums[i] > 0) break;
        
        int left = i + 1, right = n - 1;
        while (left < right) {
            int sum = nums[i] + nums[left] + nums[right];
            if (sum == 0) {
                res.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 res;
}
  • 易错点/优化点:

    1. 必须先排序,否则双指针无效。
    2. 去重是关键:i 去重 + left/right 去重(while 跳过相同元素)。
    3. nums[i] > 0 提前 break(因为后面更大,和不可能为0)。
    4. 面试追问:如果要返回所有不重复组合,怎么改?(这题已经是所有不重复了)。示例:nums = [-1,0,1,2,-1,-4] → [[-1,-1,2],[-1,0,1]]
  1. 知识点部分(双指针 + 去重模板) 排序 + 双指针去重通用模板

    • 排序后处理重复元素:if i>0 && nums[i]==nums[i-1] continue
    • 双指针移动后去重:while left<right && nums[left]==nums[left+1] left++
    • 类似题:两数之和(HashMap)、四数之和(嵌套双指针)。
    • 为什么排序?让双指针从两端逼近,O(n) 判断和。
    • 面试常问:不排序怎么做?(HashSet,但去重和时间更复杂)。
  2. 今日感悟 这道题以前刷过,但今天重点练去重和边界,才发现自己之前漏了很多重复情况。公开打卡逼着我必须写出“干净无重复”的代码,不然发出去尴尬。Day 5 了,连续5天,感觉离跳槽目标又近一步,坚持就是胜利!