454. 四数相加 II
解题思路:nums1[i] + nums2[j] + nums3[k] + nums4[l] = 0 -->
nums1[i] + nums2[j] = - nums3[k] - nums4[l]
• 时间复杂度:O(n²),其中 n 是每个数组的长度。遍历了 nums1 和 nums2 来计算哈希表中的值组合,接着遍历了 nums3 和 nums4 来查找组合。
• 空间复杂度:O(n²),哈希表中最多会存储 n² 个 n1 + n2 的组合。
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
hashTable = dict()
for n1 in nums1:
for n2 in nums2:
hashTable[n1+n2] = hashTable.get(n1+n2, 0) + 1
count = 0
for n3 in nums3:
for n4 in nums4:
# n3+n4 = -(n1+n2)
key = -(n3+n4)
if key in hashTable:
count += hashTable[key]
return count
解题思路:使用defaultdict
使用 defaultdict:
• hashMap = defaultdict(int):创建一个 defaultdict,当访问的键不存在时,它会自动初始化为 0。
• 简化了 hashMap.get(sum12, 0) + 1 的操作,只需要直接执行 hashMap[sum12] += 1。
from collections import defaultdict
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
# 使用 defaultdict 初始化
hashMap = defaultdict(int)
# 遍历 nums1 和 nums2,计算它们的和并记录在哈希表中
for n1 in nums1:
for n2 in nums2:
sum12 = n1 + n2
hashMap[sum12] += 1 # 直接增加值
count = 0
# 遍历 nums3 和 nums4,查找 -(n3 + n4) 是否存在于哈希表中
for n3 in nums3:
for n4 in nums4:
sum34 = -(n3 + n4)
if sum34 in hashMap:
count += hashMap[sum34] # 累加哈希表中的值
return count
383. 赎金信
解题思路:用hashtable解法
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
hashmap = dict()
for char in magazine:
hashmap[char] = hashmap.get(char,0) +1
for char in ransomNote:
# if char in hashmap:
# hashmap[char]-=1
# if hashmap[char] == 0:
# del hashmap[char]
# else:
# return False
if char not in hashmap or hashmap[char] == 0:
return False
hashmap[char] -= 1
return True
解题思路:collections.Counter
**减法操作 Counter(ransomNote) - Counter(magazine):
• Counter 的减法会计算两个 Counter 之间的差异。它会从 ransomNote 中每个字符的计数中减去 magazine 中对应字符的计数。
• 时间复杂度:O(n + m),其中 n 和 m 分别是 ransomNote 和 magazine 的长度。Counter 会遍历这两个字符串来统计字符的出现次数。
• 空间复杂度:O(k),其中 k是ransomNote和magazine 中不同字符的数量。
from collections import Counter
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
return not Counter(ransomNote) - Counter(magazine)
15. 三数之和
解题思路:双指针解法。需先将数据排序,后根据左右大小进行移动,小了往右大了往左,同时需跳过重复值。
• 排序的时间复杂度:O(n log n),其中 n 是数组的长度。
• 双指针的时间复杂度:外层循环是 O(n),内层双指针操作最多也是 O(n),因此双指针部分的时间复杂度为 O(n²)。
• 总时间复杂度:O(n²)。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 首先将数组排序,这样可以使用双指针技巧来优化查找
nums.sort()
result = []
# 遍历每个元素,尝试固定一个元素,然后查找其后的两个元素
for i in range(len(nums)):
# 如果当前元素大于 0,说明后续的所有元素也都会大于 0
# 因为数组已经排序好,不可能再找到三个数的和为 0,提前退出
if nums[i] > 0:
break # 优化:减少不必要的检查
# 跳过重复的元素,避免结果中出现重复的组合
if i > 0 and nums[i] == nums[i - 1]:
continue # 优化:避免重复解
# 使用双指针在 nums[i] 之后的数组中查找和为 0 的另外两个数
left, right = i + 1, len(nums) - 1
# 双指针查找
while left < right:
curSum = nums[i] + nums[left] + nums[right]
if curSum < 0:
left += 1 # 如果和小于 0,说明需要更大的数,将左指针右移
elif curSum > 0:
right -= 1 # 如果和大于 0,说明需要更小的数,将右指针左移
else:
# 找到一个解,加入结果
result.append([nums[i], 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
return result
解题思路:在遍历过程中跳过重复的元素,确保相同的组合只被计入一次。使用集合 (set) 来存储结果,因为集合可以自动去除重复的元素。
• 时间复杂度:O(n²),因为对于每个元素,内层遍历需要 O(n) 时间。
• 空间复杂度:O(n),用于存储集合和哈希表。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
result = set()
for i in range(len(nums)):
if i > 0 and nums[i] == nums[i-1]:
continue
seen = set()
for j in range(i+1, len(nums)):
complement = - nums[i] - nums[j]
if complement in seen:
result.add((nums[i], nums[j], complement))
while j + 1 < len(nums) and nums[j] == nums[j+1]:
j += 1
seen.add(nums[j])
# 将 result 中的所有元素从一种数据类型(通常是元组 tuple)转换为列表 list
return list(map(list,result))
18. 四数之和
解题思路:逻辑一致,就是复杂度比较高,loop套loop+双指针逻辑
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
# 结果存放所有满足条件的四元组
result = []
nums.sort() # 先对数组进行排序,便于后面的双指针操作
# 第一层循环:枚举第一个数字
for i in range(len(nums) - 3):
# 跳过重复的元素,避免重复结果
if i > 0 and nums[i] == nums[i - 1]:
continue
# 第二层循环:枚举第二个数字
for j in range(i + 1, len(nums) - 2):
# 跳过重复的元素
if j > i + 1 and nums[j] == nums[j - 1]:
continue
# 双指针查找剩下的两个数字
left, right = j + 1, len(nums) - 1
while left < right:
cur_sum = nums[i] + nums[j] + nums[left] + nums[right]
if cur_sum == 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 cur_sum < target:
# 当前和小于目标值,移动左指针使和变大
left += 1
else:
# 当前和大于目标值,移动右指针使和变小
right -= 1
return result