Leetcode: 三数之和

31 阅读3分钟

原题:leetcode.cn/problems/3s…

题目描述

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

**注意:**答案中不可以包含重复的三元组。

解题思路

  1. 排序预处理
    • 将数组升序排序,便于双指针操作
    • 时间复杂度 O(n log n)
  2. 固定指针遍历
    • 外层循环固定第一个数 nums[i]
    • 内层使用双指针寻找另外两数
  3. 双指针搜索
    • 左指针 left = i + 1
    • 右指针 right = n - 1
  4. 和值判断
    • 三数和 > 0:右指针左移
    • 三数和 < 0:左指针右移
    • 三数和 = 0:记录结果并移动双指针
  5. 去重处理
    • 跳过重复的 nums[i]
    • 双指针移动时跳过相同值

关键洞察

  1. 排序必要性
    • 排序后双指针能高效搜索目标值
    • 避免 O(n³) 的暴力解法
  2. 双指针优势
    • 将两数之和优化为 O(n) 操作
    • 总体复杂度降至 O(n²)
  3. 去重策略
    • 固定指针和前值比较避免重复
    • 双指针跳过相同元素防止重复组合
  4. 剪枝优化
    • nums[i] > 0 时提前终止
    • 最小三数和 > 0 时结束搜索

复杂度分析

指标说明
时间复杂度O(n²):排序 O(n log n) + 双指针 O(n²)
空间复杂度O(1) 或 O(n):取决于排序实现
最优情况O(n²):无法低于平方复杂度

代码实现

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function (nums) {
    const result = [];
    nums.sort((a, b) => a - b);

    for (let i = 0; i < nums.length - 2; i++) {
        if (i > 0 && nums[i] === nums[i - 1]) continue;
        if (nums[i] > 0) break; // No need to continue if the smallest is > 0

        let l = i + 1, r = nums.length - 1;
        while (l < r) {
            const sum = nums[i] + nums[l] + nums[r];
            if (sum === 0) {
                result.push([nums[i], nums[l], nums[r]]);
                while (l < r && nums[l] === nums[l + 1]) l++;
                while (l < r && nums[r] === nums[r - 1]) r--;
                l++;
                r--;
            } else if (sum < 0) {
                l++;
            } else {
                r--;
            }
        }
    }

    return result;
};

实际应用场景

  1. 金融分析:找出投资组合中三只股票收益和为零的组合
  2. 化学计算:寻找三种化学物质PH值之和为中性的组合
  3. 游戏设计:匹配三件装备属性之和为特定值的组合`
  4. 数据挖掘:在用户行为数据中找出三种关联行为`

相似题目