题目在leetcode上的链接为:
https://leetcode-cn.com/problems/4sum/
题目描述
解题思路
这一题与第15题 三数之和 的解题思路类似。先对数组进行从小到大的排序,然后使用两重循环遍历数组,再使用双指针遍历一遍即可。
具体步骤为:
- 首先如果 nums 为 None,或者 nums 长度小于4,那么返回空列表
- 将 nums 按照从小到大进行排序
- 使用变量 i 循环遍历 nums:
- 如果 i>0 且 nums[i]=nums[i-1],说明前一步中已经考虑了这一步可能存在的四个数的结果,那么 continue 不执行之后的代码,以此进行去重操作(第一次去重)
- 使用变量 j 循环遍历 nums[i+1:]
- 如果 j>i+1 且 nums[j]=nums[j-1],则 continue 不执行之后的代码,以此进行去重操作(第二次去重)
- 令左指针 left 为 j+1,右指针 right 为 len(nums)-1
- 以 left<right 作为判断条件进入循环:
- 如果 nums[i]+nums[j]+nums[left]+nums[right] 等于 target:
- 将找到的四个数添加到结果中
- 循环判断如果左右指针位置的数等于它门下一个位置的数时,就将指针移到下一个位置进行去重操作 (第三次去重)
- 将左右指针都移到下一个位置重新找下一个可能的结果
- 如果 nums[i]+nums[j]+nums[left]+nums[right] 小于 target,说明太小了,则将左指针向右移动一步
- 如果 nums[i]+nums[j]+nums[left]+nums[right] 大于 target,说明太大了,则将右指针向左移动一步
- 如果 nums[i]+nums[j]+nums[left]+nums[right] 等于 target:
ps: 要注意算法中标明的三次去重操作,其中第一次和第三次的去重操作与 三数之和 中的一样,特别注意第二次去重操作中的条件 j>i+1,因为当 j=i+1 时,nums[j-1]=nums[i],此时比较的 nums[j]=nums[j-1]=nums[i] 是将 i 与 j 位置的数进行比较,但我们需要比较的是 j 位置的数与它之前自己走过的前一步的数是否相同,所以需要条件 j>i+1,让 j 与 i 不相邻时再比较决定是否对 j 进行去重操作
复杂度分析:
排序操作的时间复杂度为 o(nlog(n)),三重循环的复杂度为 o(n3),由于这两步操作是顺序执行,所以总的时间复杂度为 o(nlog(n))+o(n3),即为 o(n3)。
由于只需要常数级的存储空间,所以空间复杂度为 o(1)
python代码
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
if not nums or len(nums) < 4:
return []
nums.sort()
if (target >= 0 and nums[0] > target) or (target < 0 and nums[len(nums) - 1] < target):
return []
res = []
for i in range(len(nums)):
if target >= 0 and nums[i] > target:
return res
if i > 0 and nums[i] == nums[i - 1]:
continue
for j in range(i + 1, len(nums)):
if j > i + 1 and nums[j] == nums[j - 1]:
continue
left = j + 1
right = len(nums) - 1
while left < right:
if nums[i] + nums[j] + nums[left] + nums[right] == target:
res.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 nums[i] + nums[j] + nums[left] + nums[right] > target:
right -= 1
else:
left += 1
return res