力扣454. 四数相加 II
仍然使用了defaultdict方法简化判断键值是否存在对步骤。小技巧是分组计算然后寻找对应值,将时间复杂度由暴力法的n^4降低到n^2。
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
import collections
# 除了暴力解法,可以先计算1+2数组之和存入dic,在从3+4数组中找到对应-(1+2)的值
dic_12 = defaultdict(int) # 不用defaultdict可以先行判断键是否存在,如不存在需先插入键值对
count = 0
for i in nums1:
for j in nums2:
dic_12[i + j] += 1
for m in nums3:
for n in nums4:
if -(m + n) in dic_12:
count += dic_12[-(m + n)]
return count
力扣383.赎金信
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
dic_mag = collections.defaultdict(int)
for i in magazine:
dic_mag[i] += 1
for j in ransomNote:
if j in dic_mag and dic_mag[j] != 0:
dic_mag[j] -= 1
else:
return False
return True
力扣15.三数之和
用双指针,思路稍微有点小trick,细节比较多,去重比较复杂,稍微有点难度,不过还算好理解。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 排序方便去重和剪枝
nums.sort()
s = len(nums)
result = []
for i in range(s): # i作为第一个数,left第二个数,right第三个数
left = i + 1
right = s - 1
if nums[i] > 0: # 剪枝
break
if i >= 1 and nums[i] == nums[i - 1]: #对i进行去重,上一次循环机判断的相同i与left + right的组合,注意是i-1不能是i+1(left对应的数)
continue
while left < right: # 对于每个固定位置i的left和right的组合循环
sum_ = nums[i] + nums[left] + nums[right]
if sum_ == 0:
result.append([nums[i],nums[right],nums[left]])
# 进行下一次移动前对left和right去重,由于单轮循环内,如和为0,i固定,left和left+1相同,那么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
if sum_ < 0: #组合过小,由于数组已排序,left右移和变大
left += 1
if sum_ > 0:
right -= 1
return result
力扣18.四数之和
比三数之和复杂,注意cur和pre两个都不确定,移动left和right,所以可能会出现排序后,pre最前面的指针对应的数(最小)大于target,但是和cur相加后又可以小于等于target(负数情况)。
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
# 与三数之和类似,注意存在两个变量数,如为附属,相加可能存在更小,注意left和right指针的移动条件
nums.sort()
s = len(nums)
result = []
for pre in range(s):
# 对指针pre进行剪枝
if nums[pre] > 0 and nums[pre] > target:
continue
# 对指针pre进行去重
if pre > 0 and nums[pre] == nums[pre - 1]:
continue
for cur in range(pre + 1,s):
# 对cur指针进行去重
if cur > pre + 1 and nums[cur] == nums[cur - 1]:
continue
left = cur + 1
right = s - 1
while left < right: # 当cur = n - 1时,left = n > right不进入循环
if nums[pre] + nums[cur] + nums[left] + nums[right] == target:
result.append([nums[pre],nums[cur],nums[left],nums[right]])
while left < right and nums[left] == nums[left + 1]:
left += 1 # 防止越界需要加入left < right
while left < right and nums[right] == nums[right - 1]:
right -= 1
# 不用去重时
left += 1
right -= 1
elif nums[pre] + nums[cur] + nums[left] + nums[right] > target: # 大于目标值
right -= 1
elif nums[pre] + nums[cur] + nums[left] + nums[right] < target: # 小于目标值
left += 1
return result