今天继续练习哈希表, 有部分leetcode练习题用了双指针。
454.四数相加II
思路:四个列表中每个列表出一个数字,四个相加等于0。 BruteForce 可以循环四个列表, 找到所有的组合判断是否相加为0。 时间复杂度 O(n^4) 空间复杂度 O(1)。 由于output只需要输出组合的个数, 组合的数字或者下标不需要care。 所以考虑用字典记录前两个列表数字组合相加的合出现的次数。 然后循环后两个列表, 找到哈希表对应 -num3-num4 的key对应的值即可,然后将所有这种值相加即可。时间复杂度O(n^2).
难点: 空间换时间
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
# 1. 使用 hash map 记录所有 nums1 和 nums2 元素相加的组合
record2 = defaultdict(int) # key: num1+num2, value: number of sum12 occurrences
for i in range(len(nums1)):
for j in range(len(nums2)):
record2[nums1[i]+nums2[j]] += 1
# 2. loop all elements in nums3 and nums4 and calculate sum34 = num3+num4
# find -sum34 in hash table
rlst = 0
for i in range(len(nums3)):
for j in range(len(nums4)):
sum34 = nums3[i] + nums4[j]
target = -sum34
rlst += record2[target]
return rlst
383. 赎金信
思路: 用字典记录字符串2 每个字母出现的次数, 循环字符串1,对应每个字符, 字典的key 对应的value -1。 如果字典的value 有小于0 的数字, 返回错误,反之返回True。 这道题我学习了一下 python 中 collections.Counter 的用法。
难点: 无
from collections import Counter
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
c = Counter(magazine)
c.subtract(ransomNote)
return True if min(c.values()) >= 0 else False
15. 三数之和
思路:找出一个列表中三数之和为0 的组合, bruteforce 可以循环三次做。时间复杂度 O(n^3)。 另外因为不需要输出数组的下标, 因此可以想到通过先排序在寻找, 降低时间复杂度。 排序之和, 是用双指针法,左右指针根据当前相加是否大于0, 往中间靠就可以了。
难点: 由于如果有重复的 triple 组合只需要给一个, 因此所有符合条件的triple组合写在set 中更方便。 另外, 可以加一些额外的判断条件,减少额外的循环, 但是本质上没有降低时间复杂度。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# sort the input array first
nums = sorted(nums)
# loop all element in nums, using two pointers method.
ans = set()
for i, num in enumerate(nums):
j = i+1
k = len(nums) - 1
while j < k:
if num + nums[j] + nums[k] == 0:
ans.add((num, nums[j], nums[k]))
j += 1
elif num + nums[j] + nums[k] < 0:
j += 1
else:
k -= 1
return ans
18. 四数之和
思路: 同上一题
难点: 同上一题
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums = sorted(nums)
l = len(nums)
ans = set()
for i in range(l-3):
for j in range(i+1, l-2):
left = j+1
right = l-1
while left < right:
num4sum = nums[i] + nums[j] + nums[left] + nums[right]
if num4sum == target:
ans.add((nums[i], nums[j], nums[left], nums[right]))
left += 1
right -= 1
elif num4sum < target:
left += 1
else:
right -= 1
return ans