454. 四数相加 II
题目:给你四个整数数组 nums1
、nums2
、nums3
和 nums4
,数组长度都是 n
,请你计算有多少个元组 (i, j, k, l)
能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
解题思路
思路:由于是四个独立的数组,不用考虑重复元素的情况,可以暴力遍历两次。先遍历AB,将数字和到出现次数的映射记录在hash表,然后遍历CD,求和后找到补数是否在hash表内。
- 时间复杂度:O(n^2)
- 空间复杂度:O(n^2) 最坏情况下A和B的值各不相同,相加产生的数字个数为 n^2
python
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
hashmap = {}
for n1 in nums1:
for n2 in nums2:
sum1 = n1 + n2
hashmap[sum1] = hashmap.get(sum1, 0) + 1
# 答案出现次数
count = 0
for n3 in nums3:
for n4 in nums4:
need = 0 - n3 - n4
if need in hashmap:
count += hashmap[need]
return count
总结
这种解法的关键在于利用哈希表来记录前两个数组元素之和的出现次数。这样在遍历后两个数组时,只需要查找哈希表中是否存在与当前元素之和相等的值即可。这种方法避免了直接暴力枚举四个数组的所有组合,大大提高了效率。
383. 赎金信
题目:给你两个字符串:ransomNote
和 magazine
,判断 ransomNote
能不能由 magazine
里面的字符构成。如果可以,返回 true
;否则返回 false
。 magazine
中的每个字符只能在 ransomNote
中使用一次。
解题思路
使用hash表记录magazine中字符和出现次数的映射char2cnt,然后迭代ransomNote的每个字符,看看该字符是否出现在char2cnt并且数量>0。
- 时间复杂度: O(n^2)
- 空间复杂度: O(1)
python
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
char2cnt = {} # 记录magazine中字符数量
# 词频统计
for c in magazine:
char2cnt[c] = char2cnt.get(c, 0) + 1
# 迭代判断ransomNote的字符是否在magazine里面
for c in ransomNote:
if c in char2cnt and char2cnt[c] > 0:
char2cnt[c] -= 1
else:
return False
return True
总结
通过使用哈希表记录前两个数组的所有可能和的出现次数,然后遍历后两个数组,查找其和的补数在哈希表中出现的次数,从而高效计算满足条件的元组数量。
15. 三数之和
题目:给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为 0
且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
解题思路
本题需要考虑到重复元素,可以使用双指针并且配合递归的方式实现一个通用的解决nSum的方法。具体如下:
- 1 首先对数组进行排序,这样可以方便后续的双指针操作。
- 2 然后使用递归的方式来解决 n 数之和的问题。当 n 等于 2 时,使用双指针的方式来查找满足条件的两个数。当 n 大于 2 时,递归计算 (n-1) 数之和,并将当前元素加入到结果中。
- 3 在双指针操作时,需要跳过重复的元素,以避免重复的结果。
- 时间复杂度: O(n^2)
- 空间复杂度: O(1)
python
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 1 数组排序
nums.sort()
# 2 双指针加递归计算
return self.nSumTarget(nums,3, 0, 0)
def nSumTarget(self, nums: List, n: int, start:int ,target:int)-> List[List[int]]:
''' 递归计算n数和,直到递归到2时使用双指针
Inputs:
nums: 整数数组
n: 计算n数之和
start:从start开始求n数和
target:目标和
'''
# 1 不足n元素或者n<2
res = []
sz = len(nums)
if n< 2 or sz < n:
return res
# 2 双指针计算2数和
if n == 2:
low, high = start, sz-1 # 注意1:low从start开始
while low<high:
left_val, right_val = nums[low], nums[high]
sum_val = left_val + right_val
if sum_val < target:
# low++, 并且需要跳过当前重复元素 =
while low<high and nums[low] == left_val: # 注意2:需要跳过重复元素
low += 1
elif sum_val > target:
while low<high and nums[high] == right_val:
high -= 1
else:
res.append([left_val, right_val])
# 单独移动low和high
while low<high and nums[low]==left_val: # 注意3:low和high分别移动,跳过重复元素
low += 1
while low<high and nums[high]==right_val:
high -= 1
# 3 递归计算n数和
else:
for i in range(start, sz):
# 第二次开始排除重复元素
if i > start and nums[i] == nums[i-1]:
continue
# 递归计算(n-1)Sum
sub_res = self.nSumTarget(nums, n-1, i+1, target-nums[i])
for arr in sub_res:
arr.append(nums[i])
res.append(arr)
return res
总结
利用了排序和双指针的技巧,并通过递归的方式来解决 n 数之和的问题。虽然时间复杂度为 O(n^2),但是空间复杂度较低,并且代码实现也比较简洁。需要时刻注意排除重复元素。
18. 四数之和
题目:给你一个由 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
你可以按 任意顺序 返回答案 。
解题思路
同"三数之和"。
- 时间复杂度: O(n^2)
- 空间复杂度: O(1)
python
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
# 1 数组排序
nums.sort()
# 2 双指针加递归计算
return self.nSumTarget(nums,4, 0, target)
def nSumTarget(self, nums: List, n: int, start:int ,target:int)-> List[List[int]]:
''' 递归计算n数和,直到递归到2时使用双指针
Inputs:
nums: 整数数组
n: 计算n数之和
start:从start开始求n数和
target:目标和
'''
# 1 不足n元素或者n<2
res = []
sz = len(nums)
if n< 2 or sz < n:
return res
# 2 双指针计算2数和
if n == 2:
low, high = start, sz-1 # 注意1:low从start开始
while low<high:
left_val, right_val = nums[low], nums[high]
sum_val = left_val + right_val
if sum_val < target:
# low++, 并且需要跳过当前重复元素 =
while low<high and nums[low] == left_val: # 注意2:需要跳过重复元素
low += 1
elif sum_val > target:
while low<high and nums[high] == right_val:
high -= 1
else:
res.append([left_val, right_val])
# 单独移动low和high
while low<high and nums[low]==left_val: # 注意3:low和high分别移动,跳过重复元素
low += 1
while low<high and nums[high]==right_val:
high -= 1
# 3 递归计算n数和
else:
for i in range(start, sz):
# 第二次开始排除重复元素
if i > start and nums[i] == nums[i-1]:
continue
# 递归计算(n-1)Sum
sub_res = self.nSumTarget(nums, n-1, i+1, target-nums[i])
for arr in sub_res:
arr.append(nums[i])
res.append(arr)
return res
总结
同三数之和,背下nSumTarget就能一劳永逸的解决N数和问题啦~