三数之和——JS实现

286 阅读2分钟

15. 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

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

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1][-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0

提示:

  • 3 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

思路:

已知三个数加起来为0,可以简化成确定一个数tmp,找出两个数相加为0-tmp

已知数组中可能存在重复项,可以使用排序算法先进行排序

let arr = nums.sort((a, b) => a - b)
  • sort 方法:

    • 用于对数组的元素进行排序,并返回数组
    • 若无参数,默认调用数组中每一项的toString方法,按照unicode编码进行排序
    • 对于两位数来说,规则是按照每一项第一位比较,相同则第二位,如果是2和13比较,2的unicode是32,1的unicode是31,得出2比13大明显是不对的。
    • sort函数可以接收一个函数参数:升序 return a-b

主要思路:

排序后取第一个数,以第一个数arr[i]为基准,找到第一个数之后范围内相加等于0-arr[i]的即可

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function (nums) {
    let arr = nums.sort((a, b) => a - b)
    let result = []
    let tmp, left, right
    //循环遍历数组中的所有数
    for (let i = 0; i < arr.length; i++) {
        // 如果第一个数大于0,而数组是升序,已知往后的数都大于0,则相加不可能为0
        if (arr[i] > 0) break
        // 如果前一个数与当前数相同,则可以直接跳过,防止所得答案重复
        while (arr[i] == arr[i - 1]) i++
        // 找到相加等于tmp的数,三数之和为0
        tmp = 0 - arr[i]
        // 从i后开始寻找
        left = i + 1
        // 到长度-1截至
        right = arr.length - 1
        // 类似快排两边寻找
        while (left < right) {
            // 满足条件
            if (arr[left] + arr[right] == tmp) {
                let tmparr = []
                tmparr.push(arr[i], arr[left], arr[right])
                result.push(tmparr)
                // 若区间内存在重复的两个数可以直接跳过,否则答案有重复
                while (left < right && arr[left] == arr[left + 1]) left++
                while (left < right && arr[right] == arr[right - 1]) right--
                left++
                right--
                // 若比基准大,则说明right的数较大,左移寻找小值
            } else if (arr[left] + arr[right] > tmp) {
                right--
                // 若比基准小,则说明left的数较小,右移寻找小=大值
            } else if (arr[left] + arr[right] < tmp) {
                left++
            }
        }
    }
    
    console.log(result)
    return result
};