LeetCode 15 三数之和 | 刷题打卡

269 阅读2分钟

题目描述

本题选自 LeetCode 15. 三数之和

题目描述: 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 abc ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

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

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:

输入:nums = []
输出:[]

示例 3:

输入:nums = [0]
输出:[]

解题思路

暴力三重循环显然不是最优解。

这里,第一种思路是借鉴 LeetCode 1. 两数之和 的想法,基于 Map 或者 Set,三数之和相当于在两数之和的基础上增加一层循环。

第二种思路是,我们知道如果要 a + b === 0 那么有三种可能:

  • a = b = 0
  • a < 0 & b > 0
  • a > 0 & b < 0

因此,一个有序数组我们可以通过两边逼近的方式优化循环的查找过程。

题解

  • 两数之和的 Map 解法
var twoSum = function (nums, target) {
    let numMap = new Map([]);
    for (let i = 0; i < nums.length; i++) {
        let j = numMap.get(target - nums[i])
        if (j !== undefined && j !== i) {
            return [i, j];
        } else {
            numMap.set(nums[i], i);
        }
    }
};
  • 三数之和的 Set 解法
var threeSum = function (nums) {
    if (nums.length < 3) {
        return [];
    }
    let arr = nums.sort();
    let res = new Set();
    for (let i = 0; i < arr.length; i++) {
        if (i > 0 && arr[i - 1] === arr[i]) continue;
        let set = new Set([]);
        let a = arr[i];
        for (let j = i + 1; j < arr.length; j++) {
            let b = arr[j];
            let c = -a - b;
            if (set.has(c)) {
                res.add([a, b, c].join(','));
            } else {
                set.add(b);
            }
        }
    }
    return [...res].map(val => val.split(','));
};
  • 三数之和使用游动指标进行两边逼近的解法
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function (nums) {
    if (nums.length < 3) {
        return [];
    }
    let arr = nums.sort((a, b) => a - b);
    let res = []
    for (let i = 0; i < arr.length; i++) {
        if (i > 0 && arr[i - 1] === arr[i]) continue;
        let set = new Set([]);
        let l = i + 1;
        let r = nums.length - 1;
        while (l < r) {
            let sum = arr[i] + arr[l] + arr[r];
            if (sum < 0) {
                l++;
            } else if (sum > 0) {
                r--;
            } else {
                res.push([arr[i], arr[l], arr[r]]);
                while (l < r && nums[l] === nums[l + 1]) l++;
                while (l < r && nums[r] == nums[r - 1]) r--;
                l++;
                r--;
            }
        }
    }
    return res;
};

总结

在解题过程中,我们预先进行数组排序,可以跳过一些重复的选项

前期回顾

Leetcode303 区域和检索 | 刷题打卡

LeetCode 组合总和三连 | 刷题打卡

LeetCode 703 数据流中的第 K 大元素 | 刷题打卡

LeetCode 239 滑动窗口最大值 | 刷题打卡

LeetCode 242 有效的字母异位词 | 刷题打卡