题目:
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
-
0 <= a, b, c, d < n -
a、b、c和d互不相同 -
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 问题时,核心思路是结合排序和双指针技术。首先将数组按升序排列,这样可以利用数值的有序性来优化搜索过程。然后,使用两个指针 i 和 j,分别从数组的起始和末尾开始移动。通过这种方式,可以灵活地控制 nums[i] 和 nums[j] 两数之和的大小:
-
当希望两数之和增大时,将
i指针向右移动,这样可以选取更大的数值。 -
当希望两数之和减小时,将
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. 双指针查找后两个数
在固定了前两个数之后,使用双指针技术来查找后两个数。初始化两个指针 k 和 l,其中 k 从 j + 1 开始,l 从数组末尾开始。通过移动这两个指针,可以高效地找到所有可能的后两个数,使得四个数的和等于目标值。
4. 去重操作
在每一步中,都需要跳过重复的数,以避免重复解。具体来说:
- 在外层循环中,如果当前数与前一个数相同,则跳过。
- 在内层循环中,如果当前数与前一个数相同,则跳过。
- 在找到符合条件的四元组后,移动指针时也需要跳过所有重复的数。
5. 边界条件处理
在开始遍历之前,先检查数组的长度是否小于4,如果是,则直接返回空列表,因为无法找到四个数的组合。
&spm=1001.2101.3001.5002&articleId=146556343&d=1&t=3&u=9b319a3de6a340958a41ef8d5465e936)
923

被折叠的 条评论
为什么被折叠?



