LeetCode18、 四数之和

58 阅读1分钟

LeetCode 系列记录我学习算法的过程。

持续创作,加速成长!这是我参与「掘金日新计划 6 月更文挑战」的第 17 天,点击查看活动详情

题目

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abcd 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

示例:

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

输入: nums = [2,2,2,2,2], target = 8
输出: [[2,2,2,2]]

提示

  • 1 <= nums.length <= 200
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109

思路

这题我的思路和三数之和差不多,只不过多了一重循环,还有判断条件有所改变:

  • 首先也是判断数组长度,不足 4 直接返回空数组
  • 然后进行升序排序,创建记录答案的 res 及记录遍历过的组合 map 两个变量
  • 双重循环进行遍历,进行下一步前先判断当前两数组合有没有遍历过,有则跳过,无则记录到 map
  • 头尾两指针指向下一坐标及尾坐标,判断四数之和与 target
  • 相等则记录答案,移动头尾指针并跳过相同项
  • 不相等则视情况而定移动头指针或尾指针
  • 当头尾指针相遇后结束本轮循环

代码实现

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[][]}
 */
var fourSum = function(nums, target) {
    const len = nums.length
    if(len < 4) return [] // 数组
    nums.sort((a, b) => a - b) // 排序
    const res = [],  // 答案
          map = new Map() // 记录遍历过的组合

    // 遍历数组
    for(let i = 0; i < len - 3; i++) {
        const l1 = nums[i]
        // 第二重遍历
        for(let j = i + 1; j < len - 2; j++) {
            const l2 = nums[j]
            // 将当前两数组合,判断是否遍历过,是则跳入下一循环,不是则记录
            const key = JSON.stringify([l1, l2])
            if (map.has(key)) continue
            map.set(key, true)
            // 取下一下标及尾下标
            let x = j + 1,
                y = len - 1
            while(x < y) {
                // 取和
                const sum = l1 + l2 + nums[x] + nums[y]
                // 相等则记录答案,移动 x y 并跳过相同项
                if (sum === target) {
                    res.push([l1, l2, nums[x], nums[y]])
                    do { x++ } while (nums[x] === nums[x - 1] && x < y)
                    do { y-- } while (nums[x] === nums[y + 1] && x < y)
                } else if (sum < target) {
                    // 小于答案则移动 x
                    do { x++ } while (nums[x] === nums[x - 1] && x < y)
                } else {
                    // 大于答案则移动 y
                    do { y-- } while (nums[x] === nums[y + 1] && x < y)
                }
            }
        }
    }

    return res
};

image.png