18. 四数之和 - 力扣(LeetCode)

题目:

        给你一个由 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

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= nums.length <= 200

  • -109 <= nums[i] <= 109

  • -109 <= target <= 109


思路如下:

        解决 nSum 问题时,核心思路是结合排序和双指针技术。首先将数组按升序排列,这样可以利用数值的有序性来优化搜索过程。然后,使用两个指针 ij,分别从数组的起始和末尾开始移动。通过这种方式,可以灵活地控制 nums[i]nums[j] 两数之和的大小:

  1. 当希望两数之和增大时,将 i 指针向右移动,这样可以选取更大的数值。

  2. 当希望两数之和减小时,将 j 指针向左移动,这样可以选取更小的数值。

    拓展到该题,需要求四数之和,思路与三数之和(15. 三数之和 - 力扣(LeetCode)-CSDN博客)类似,但需要用到 4 个指针。


题解如下:

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
​
        nums.sort()
         res = []
        n = len(nums)
​
        if n < 4:
            return res
        
        # 外层循环遍历第一个数
        for i in range(n - 3):
            # 跳过重复的i,避免重复解
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            
            # 内层循环遍历第二个数
            for j in range(i + 1, n - 2):
                # 跳过重复的j,避免重复解
                if j > i + 1 and nums[j] == nums[j - 1]:
                    continue
                
                # 初始化双指针,k从j+1开始,l从数组末尾开始
                k = j + 1
                l = n - 1
                
                # 双指针查找另外两个数
                while k < l:
                    # 计算当前四个数的和
                    sums = nums[i] + nums[j] + nums[k] + nums[l]
                    
                    # 如果和大于目标值,移动右指针l向左
                    if sums > target:
                        l -= 1
                    # 如果和小于目标值,移动左指针k向右
                    elif sums < target:
                        k += 1
                    # 如果和等于目标值
                    else:
                        # 将这四个数加入结果列表
                        res.append([nums[i], nums[j], nums[k], nums[l]])
                        
                        # 跳过所有重复的k值,避免重复解
                        while k < l and nums[k] == nums[k + 1]:
                            k += 1
                        # 移动k指针
                        k += 1
                        
                        # 跳过所有重复的l值,避免重复解
                        while k < l and nums[l] == nums[l - 1]:
                            l -= 1
                        # 移动l指针
                        l -= 1
        
        # 返回最终结果
        return res

题解示例:

​
假设输入数组为 nums = [1, 0, -1, 0, -2, 2],目标值为 target = 0。
​
排序数组:
排序后的数组为 [-2, -1, 0, 0, 1, 2]。
​
外层循环遍历第一个数:
i = 0,选择 nums[0] = -2。
跳过重复的 i。
​
内层循环遍历第二个数:
j = 1,选择 nums[1] = -1。
跳过重复的 j。
​
双指针查找另外两个数:
初始化 k = 2,l = 5。
计算和 sums = -2 + -1 + 0 + 2 = -1,小于目标值,移动 k 向右。
继续计算和,直到找到等于目标值的组合。
​
找到符合条件的四元组:
[-2, -1, 1, 2] 和为 0。
[-2, 0, 0, 2] 和为 0。
[-1, 0, 0, 1] 和为 0。
​
所以最终结果为 [[ -2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]]。
​

逻辑梳理:

1. 排序数组

        首先对数组进行排序,这样可以方便后续的去重操作和双指针查找。排序后的数组是有序的,这使得我们可以通过移动指针来快速调整和的大小。

2. 双层循环固定前两个数

        使用两层循环分别固定前两个数 nums[i]nums[j]。外层循环遍历第一个数,内层循环遍历第二个数。这样可以确保我们遍历所有可能的前两个数的组合。

3. 双指针查找后两个数

        在固定了前两个数之后,使用双指针技术来查找后两个数。初始化两个指针 kl,其中 kj + 1 开始,l 从数组末尾开始。通过移动这两个指针,可以高效地找到所有可能的后两个数,使得四个数的和等于目标值。

4. 去重操作

        在每一步中,都需要跳过重复的数,以避免重复解。具体来说:

  • 在外层循环中,如果当前数与前一个数相同,则跳过。
  • 在内层循环中,如果当前数与前一个数相同,则跳过。
  • 在找到符合条件的四元组后,移动指针时也需要跳过所有重复的数。

5. 边界条件处理

        在开始遍历之前,先检查数组的长度是否小于4,如果是,则直接返回空列表,因为无法找到四个数的组合。

你可能感兴趣的:(#,数组,leetcode,算法,python,数据结构,数组)