第一题:四数之和
来源:https://leetcode.cn/problems/4sum/description/
题目:
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复 的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < na、b、c和d互不相同nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
python
from typing import List
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
n = len(nums)
result = []
for i in range(n - 3):
# 去重第一个数
if i > 0 and nums[i] == nums[i - 1]:
continue
for j in range(i + 1, n - 2):
# 去重第二个数
if j > i + 1 and nums[j] == nums[j - 1]:
continue
left = j + 1
right = n - 1
while left < right:
total = nums[i] + nums[j] + nums[left] + nums[right]
if total == target:
result.append([nums[i], nums[j], nums[left], nums[right]])
# 去重第三个数
while left < right and nums[left] == nums[left + 1]:
left += 1
# 去重第四个数
while left < right and nums[right] == nums[right - 1]:
right -= 1
left += 1
right -= 1
elif total < target:
left += 1
else:
right -= 1
return result
这个题和前面的"三数之和"差不多,就是多了一个数字而已。
我的思路仍然是降维,将四数之和转换为两数之和。先对数组进行排序,先固定前两个数,将问题简化为在剩下的区间里找两数之和,使四数之和等于题目中所给的target,用双指针寻找后两个数,同时跳过重复元素,避免生成重复的四元组。
我用题目中所给的示例进行模拟验证:
示例:nums = [1,0,-1,0,-2,2],target = 0
步骤1:排序
原数组:[1,0,-1,0,-2,2]
排序后的数组:[-2,-1,0,0,1,2],len(nums) = 6
步骤2:第一层循环(i从0开始)
i = 0,nums[i] = -2,进入第二层循环,j从j + 1开始
j = 1,nums[j] = -1,初始化left = 2,right = 5,nums[2] = 0,nums[5] = 2,进入循环;
total = nums[i] + nums[j] + nums[left] + nums[right] = -2 - 1 + 0 + 2 = -1 < target,left += 1;
此时left = 3,nums[left] = 0,进入循环
total = nums[i] + nums[j] + nums[left] + nums[right] = - 2 - 1 + 0 + 2 = - 1 < target,left += 1;
此时left = 4,nums[left] = 1,进入循环
total = nums[i] + nums[j] + nums[left] + nums[right] = - 2 - 1 + 1 + 2 = 0 == target,加入result。
做去重检查:检查nums[left]和nums[left + 1],无重复,nums[right]和nums[right - 1],无重复;
left += 1,right -= 1,此时left = 5 > right,退出循环。
j = 2,nums[j] = 0
初始化left = 3,right = 5,nums[left] = 0,nums[right] = 2,进入循环;
total = nums[i] + nums[j] + nums[left] + nums[right] = - 2 + 0 + 0 + 2 = 0 == target,加入result;
做去重检查:检查nums[left]和nums[left + 1],无重复,nums[right]和nums[right - 1],无重复;
left += 1,right -= 1,此时left = 4,right = 4,退出循环。
j = 3,nums[j] = 0(此情况下也存在重复现象,可直接排除)
初始化left = 4,right = 5,nums[left] = 1,nums[right] = 2,进入循环;
total = nums[i] + nums[j] + nums[left] + nums[right] = - 2 + 0 + 1 + 2 = 1 > target,right -= 1;
此时right = 4,退出循环。
j = 4,nums[j] = 1
初始化left = 5,right = 5,退出循环;
i = 1,nums[i] = -1,进入第二层循环,j从j + 1开始
j = 2,nums[j] = 0,初始化left = 3,right = 5,nums[left] = 0,nums[right] = 2,进入循环;
total = nums[i] + nums[j] + nums[left] + nums[right] = - 1 + 0 + 0 + 2 = 1 > target,right -= 1;
此时right = 4,nums[right] = 1,进入循环
total = nums[i] + nums[j] + nums[left] + nums[right] = - 1 + 0 + 0 + 1 == target,加入result;
做去重检查:nums[left]和nums[left + 1],无重复,nums[right]和nums[right - 1],无重复;
left += 1,right -= 1,left = 4 > right,退出循环。
i = 2,nums[i] = 0,进入第二层循环,j从j + 1开始
j = 3,nums[j] = 0,初始化left = 4,right = 5,nums[left] = 1,nums[right] = 2,进入循环;
total = nums[i] + nums[j] + nums[left] + nums[right] = 0 + 0 + 1 + 2 = 3 > target,right -= 1;
此时right = 4,退出循环。
最终结果:[-1,0,0,1],[-2,0,0,2],[-2,-1,1,2],与示例一致。
记录完毕,收工。