美文网首页
18. 四数之和

18. 四数之和

作者: Still_Climbing | 来源:发表于2024-03-27 09:54 被阅读0次

题目链接:国际版国内版
公司:Meta
解法:双指针、递归

题目描述

Given an array nums of n integers, return an array of all the unique quadruplets [nums[a], nums[b], nums[c], nums[d]] such that:

  • 0 <= a, b, c, d < n
  • a, b, c, and d are distinct.
  • nums[a] + nums[b] + nums[c] + nums[d] == target

You may return the answer in any order.

Example 1:

Input: nums = [1,0,-1,0,-2,2], target = 0
Output: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

Example 2:

Input: nums = [2,2,2,2,2], target = 8
Output: [[2,2,2,2]]

思路

如果你已经做过 2sum3sum 了,那么这道题的题目描述你应该已经很熟悉了,即:在一个无序且有重复的数组中找到四个元素,使它们的和为 0,返回所有可能的结果。看到这里,我们首先先来回忆一下 3sum 的解法,即:将数组排好序,每次固定一个元素 nums[i],再在剩余的子数组 nums[i+1:] 中找 2sum 结果为 target - nums[i] 的两个元素即可。那么以此类推,对于这道 4sum,我们也可以将数组排好序之后固定一个元素,在剩下的数组元素中找 3sum。这种思路的参考代码如下:

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        """ 固定住第一个元素,对后续元素进行threeSum,注意去重 """
        def three_sum(nums, start, target):
            def two_sum(numbers, start_idx, target):
                res = []
                i, j = start_idx, len(numbers) - 1
                while i < j:
                    tmp = numbers[i] + numbers[j]
                    left, right = numbers[i], numbers[j]
                    if tmp < target:
                        while i < j and numbers[i] == left: i += 1
                    elif tmp > target:
                        while i < j and numbers[j] == right: j -= 1
                    else:
                        res.append([i, j])
                        while i < j and numbers[i] == left: i += 1
                        while i < j and numbers[j] == right: j -= 1
                return res
            res = [] 
            i = start
            while i < len(nums):
                tuples = two_sum(nums, i + 1, target - nums[i])
                for j, k in tuples:
                    res.append([i, j, k])
                while i < len(nums) - 1 and nums[i + 1] == nums[i]:
                    i += 1
                i += 1
            return res


        nums.sort()
        res = []
        a = 0
        while a < len(nums):
            tuples = three_sum(nums, a + 1, target - nums[a])
            for b, c, d in tuples:
                res.append([nums[a], nums[b], nums[c], nums[d]])
            while a < len(nums) - 1 and nums[a + 1] == nums[a]:
                a += 1
            a += 1
        return res

这种解法可以解题,但存在一个问题,即:如果面试的时候面试官问你 5sum、6sum 怎么写,难道我们还能从 2sum 开始一层一层地写下去么?为此我们再次观察一下思路:求 4sum 我们需要知道 3sum,求解 3sum 我们需要知道 2sum,求解 2sum 就可以直接在 O(N) 的时间内算出来了。因此,求解 nSum 问题,我们需要知道 (n-1)Sum 的解,这就变成了一个递归的解法。同时,递归的终止条件是 2sum。参考代码如下:

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        """通用解法"""
        def nSum(nums, n, start, target):
            res = []
            if n < 2:
                return res
            if n == 2:
                i, j = start, len(nums) - 1
                while i < j:
                    curr = nums[i] + nums[j]
                    left, right = nums[i], nums[j]
                    if curr < target:
                        # 去重
                        while i < j and nums[i] == left:
                            i += 1
                    elif curr > target:
                        # 去重
                        while i < j and nums[j] == right:
                            j -= 1
                    else:
                        res.append([left, right])
                        # 去重
                        while i < j and nums[i] == left:
                            i += 1
                        while i < j and nums[j] == right:
                            j -= 1
                return res
            else:
                i = start
                while i < len(nums):
                    tmp = nSum(nums, n - 1, i + 1, target - nums[i])
                    for tmp_res in tmp:
                        tmp_res.append(nums[i])
                        res.append(tmp_res)
                    # 去重
                    while i < len(nums) - 1 and nums[i + 1] == nums[i]:
                        i += 1
                    i += 1
            return res
        
        nums.sort()
        return nSum(nums, 4, 0, target)

我们这里定义了一个名为 nSum 的 helper function,它的作用就是对于给定的数组,从中找出 n 个数,使其和为 target。退出条件如之前所述,是 n == 2 的时候,就演变为了 2sum。当 n > 2 的时候,我们每次需要固定一个元素,再在剩下的元素中寻找 (n-1)sum。对于返回的每一个可能的组合,我们将其拼装成最后的结果,即在列表中加上所固定的那个元素即可。

对于时间复杂度分析,我们需要看递归树的深度。假设数组长度为 N,我们要求 k sum,由于递归退出的条件是 k = 2,因此总的递归树深度应该为 k - 1,时间复杂度应该为 O(N^(k-1))。对于空间复杂度分析,我们主要考虑递归需要的栈的空间。由于递归树深度为 k -1,因此栈的空间复杂度应该为 O(k-1),在最坏情况下 k 应该等于 n,则空间复杂度为 O(N)

相关文章

  • 【Leetcode算法题】18. 四数之和

    By Long Luo 18. 四数之和[https://leetcode-cn.com/problems/4su...

  • LeetCode-18 四数之和

    题目:18. 四数之和 难度:中等 分类:数组 解决方案:双指针 今天我们学习第18题四数之和,这是一道中等题。像...

  • 力扣每日一题:18.四数之和

    18.四数之和 https://leetcode-cn.com/problems/4sum/[https://le...

  • 18.四数之和

    18.四数之和 题目链接:https://leetcode-cn.com/problems/4sum/[https...

  • 18. 四数之和

    一、题目原型: 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四...

  • 18. 四数之和

    知乎ID: 码蹄疾码蹄疾,毕业于哈尔滨工业大学。小米广告第三代广告引擎的设计者、开发者;负责小米应用商店、日历、开...

  • 18. 四数之和

    18.四数之和 给定一个包含n个整数的数组nums和一个目标值target,判断nums中是否存在四个元素a,b,...

  • 18.四数之和

    给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,...

  • 18. 四数之和

    一、题目 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素...

  • 18.四数之和

    自己解法 四数之和解题思路和三数之和类似,不过这个方式是固定前两个数字,后面两个数字用夹逼的方式向中间逼近,这样时...

网友评论

      本文标题:18. 四数之和

      本文链接:https://www.haomeiwen.com/subject/nizetjtx.html