454.四数相加II
思路
和昨天的两数之和类似。
- 遍历前两个数组,统计两个数组元素之和,和出现的次数,放到map中。key放a和b两数之和,value放a和b两数之和出现的次数。
- 遍历后两个数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
代码
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
hashmap = dict()
for i in nums1:
for j in nums2:
hashmap[i+j] = hashmap.get(i+j, 0) + 1
count = 0
for i in nums3:
for j in nums4:
count += hashmap.get(-i-j, 0)
return count
383. 赎金信
思路
与昨天的前两题思路相似。
在本题的情况下,使用map的空间消耗要比数组大一些,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的。数据量大的话就能体现出来差别了。 所以数组更加简单直接有效。
代码
数组法
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
ransom_count = [0] * 26
magazine_count = [0] * 26
for c in ransomNote:
ransom_count[ord(c) - ord('a')] += 1
for c in magazine:
magazine_count[ord(c) - ord('a')] += 1
return all(ransom_count[i] <= magazine_count[i] for i in range(26))
哈希表法
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
hashmap = dict()
for s in magazine:
hashmap[s] = hashmap.get(s, 0) + 1
for ss in ransomNote:
if hashmap.get(ss, 0) > 0:
hashmap[ss] = hashmap.get(ss) - 1
else:
return False
return True
Counter法
from collections import Counter
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
return not Counter(ransomNote) - Counter(magazine)
15. 三数之和
思路
- 题目中说不可以包含重复的三元组。用哈希法找到所有符合条件的三元组再去重是非常费时的。
- 用双指针法,首先将数组排序。然后有一层for循环,i从下标0的地方开始,同时定一个下标left定义在i+1的位置上,定义下标right在数组结尾的位置上。找nums[i]+nums[left]+nums[right]=0。如果nums[i] + nums[left] + nums[right] > 0就说明 此时三数之和大了,所以right下标就应该向左移动;如果 nums[i] + nums[left] + nums[right] < 0说明此时三数之和小了,left 就向右移动,直到left与right相遇为止。
- a, b, c都要去重,详见代码。
代码
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
result = []
nums.sort()
for i in range(len(nums)):
# 如果第一个元素已经大于0,不需要进一步检查
if nums[i] > 0:
return result
# 跳过相同的元素以避免重复
# 不能有重复的三元组,但三元组内的元素是可以重复的,所以与i-1比较
if i > 0 and nums[i] == nums[i - 1]:
continue
left = i + 1
right = len(nums) - 1
while right > left:
sum_ = nums[i] + nums[left] + nums[right]
if sum_ < 0:
left += 1
elif sum_ > 0:
right -= 1
else:
result.append([nums[i], nums[left], nums[right]])
# 要先保存一个,再进行后面的去重判断,考虑列表元素都是0的情况
# 跳过相同的元素以避免重复
while right > left and nums[right] == nums[right - 1]:
right -= 1
while right > left and nums[left] == nums[left + 1]:
left += 1
right -= 1
left += 1
return result
18. 四数之和
思路
和上一题是一个思路,都是使用双指针法, 只不过是在上一题的基础上再套一层for循环。但在剪枝时不能只看是否大于target,因为target有可能是负数,要想剪枝需要添加一些限定条件。
代码
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
n = len(nums)
result = []
for i in range(n):
if nums[i] > target and nums[i] > 0 and target > 0:# 剪枝(可省)
break
if i > 0 and nums[i] == nums[i-1]:# 去重
continue
for j in range(i+1, n):
if nums[i] + nums[j] > target and target > 0: #剪枝(可省)
break
if j > i+1 and nums[j] == nums[j-1]: # 去重
continue
left, right = j+1, n-1
while left < right:
s = nums[i] + nums[j] + nums[left] + nums[right]
if s == 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 s < target:
left += 1
else:
right -= 1
return result
每日总结
前两个题是跟昨天类似的,后两个双指针的思路稍微复杂一些,要认真练习写一下。