Leetcode 18. 四数之和

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:

答案中不可以包含重复的四元组。

示例:

给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。



满足要求的四元组集合为:

[

  [-1,  0, 0, 1],

  [-2, -1, 1, 2],

  [-2,  0, 0, 2]

]

**难度**: Medium

**标签**: 数组、 哈希表、 双指针、


# -*- coding: utf-8 -*-
# @Author  : LG

"""
行用时:1808 ms, 在所有 Python3 提交中击败了14.35% 的用户
内存消耗:13.5 MB, 在所有 Python3 提交中击败了97.14% 的用户

解题思路:
    双指针法,总体思路同三数求和

      i  j l                                      r
    [-7,-5,0,7,1,1,-10,-2,7,7,-2,-6,0,-10,-5,7,-8,5], 28
    外层i, j双循环, l, r双指针分别指向头尾。
"""
class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        n = len(nums)
        if n < 4:       # 长度小于4,直接返回[]
            return []

        result = []
        now_i = None
        for i in range(n):
            if nums[i] == now_i:    # i去重
                continue
            now_i = nums[i]

            now_j = None
            for j in range(i + 1, n):
                if nums[j] == now_j:    # j去重
                    continue
                now_j = nums[j]

                l, r = j + 1, n - 1     # 双指针分别指向剩余字符串的头尾
                while l < r:
                    if nums[i] + nums[j] + nums[l] + nums[r] == target:     # 若相等
                        result.append([nums[i], nums[j], nums[l], nums[r]])
                        while l < r and nums[l] == nums[l + 1]: # 左指针去重
                            l += 1
                        while l < r and nums[r] == nums[r - 1]: # 右指针去重
                            r -= 1
                        l += 1  # 由于相等,且已排序去重。左右指针可同时向中间移动
                        r -= 1
                    elif nums[i] + nums[j] + nums[l] + nums[r] < target:    # 和小,移动左指针
                        l += 1
                    else:   # 和大,移动右指针
                        r -= 1
        return result

"""
执行用时:124 ms, 在所有 Python3 提交中击败了76.55% 的用户
内存消耗:13.7 MB, 在所有 Python3 提交中击败了52.62% 的用户

解题思路:
    对上述代码进行优化后,速度进一步提升
    可将每次的索引值保存下来,如 num_i = nums[i],免去每次索引应该会更快一点
"""
class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        n = len(nums)
        if n < 4:
            return []

        result = []
        now_i = None

        for i in range(n - 3):
            if nums[i] == now_i:
                continue
            now_i = nums[i]

            if nums[i] * 4 > target:    # 当前4倍的最小值大于目标值,则后续均大于,跳出循环
                break
            if nums[i] + nums[-1] * 3 < target: # 当前最小值与3倍的最大值的和小于目标值,跳出本次循环
                continue

            now_j = None
            for j in range(i + 1, n - 2):
                if nums[j] == now_j:
                    continue
                now_j = nums[j]

                if nums[i] + nums[j] * 3 > target:  # 优化
                    break
                if nums[i] + nums[j] + nums[-1] * 2 < target:   # 优化
                    continue

                l, r = j + 1, n - 1
                while l < r:
                    if nums[i] + nums[j] + nums[l] + nums[r] == target:
                        result.append([nums[i], nums[j], nums[l], nums[r]])
                        while l < r and nums[l] == nums[l + 1]:
                            l += 1
                        while l < r and nums[r] == nums[r - 1]:
                            r -= 1
                        l += 1
                        r -= 1
                    elif nums[i] + nums[j] + nums[l] + nums[r] < target:
                        l += 1
                    else:
                        r -= 1
        return result