暴力解法:四重循环;或者一个哈希表,然后三重循环
看了解题思路之后:两个两重循环,先统计两个数组的和及其出现次数,然后再循环另外两个数组
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
from collections import defaultdict
sum_12 = defaultdict(int)
for i in nums1:
for j in nums2:
sum_12[i+j] += 1
count = 0
for i in nums3:
for j in nums4:
key = 0 - i - j
if key in sum_12:
count += sum_12[key]
return count
注意点:magazine中每个字符只能使用一次,所以每次使用后需要减一
使用哈希表统计magazine的字符及出现次数,然后遍历ransomNote
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
from collections import defaultdict
temp = defaultdict(int)
for i in magazine:
temp[i] += 1
for i in ransomNote:
if i not in temp:
return False
if temp[i] <= 0:
return False
temp[i] -= 1
return True
看了题解之后,可以使用数组,因为两个字符串都是由小写字母组成
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
# 因为范围限定了英文小写字母,所以可以使用数组,和字母异位词类似
record = [0] * 26
for i in magazine:
record[ord(i) - ord('a')] += 1
for i in ransomNote:
record[ord(i) - ord('a')] -= 1
if record[ord(i) - ord('a')] < 0:
return False
return True
注意点:不可以包含重复的三元组,除了索引不能相同,还有就是结果中的多个三元组也不能重复,这种情况导致了题目复杂度增加
看了题解之后,了解了双指针法。因为本题是返回数组元素,不是索引值,所以可以排序使用双指针法
python小知识:nums.sort()为原地排序
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 因为最后返回的是元素,可以进行排序,然后使用双指针
res = []
nums.sort()
for i in range(len(nums)):
if nums[i] > 0: # 已经进行排序了,如果当前最小的值都>0了,后续不可能有三个值相加为0的
break
if i > 0 and nums[i] == nums[i-1]: # 对a进行去重;如果a前面的数值和a相等,那么b+c=-a等组合已经寻找过了,没有必要再来一次
continue
left = i+1
right = len(nums) - 1
while left < right: # 因为索引不能相同,left==right是没有用的
if nums[left] + nums[right] + nums[i] > 0:
right -= 1
elif nums[left] + nums[right] + nums[i] < 0:
left += 1
else:
res.append([nums[i], nums[left], nums[right]])
# 对b和c去重
while left < right and nums[left] == nums[left+1]:
left += 1
while left < right and nums[right] == nums[right-1]:
right -= 1
# =0后left和right都需要移动一步
left += 1
right -= 1
return res
四数之和与三数之和思路是一样的,三数之和是一层循环+双指针,四数之和是两层循环+双指针
题目中有个地方有差异,三数之和是等于0,四数之和是等于target,这个会导致剪枝的条件不同
从四数之和可以更好的理解三数之和的剪枝和去重操作
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
res = []
# 因为要使用双指针,先排序
nums.sort()
# 使用双重循环+双指针
for i in range(len(nums)):
# 第一重循环 剪枝
if nums[i] > target and nums[i] >= 0:
break
# 第一重循环 去重
if i > 0 and nums[i] == nums[i-1]:
continue
for j in range(i+1, len(nums)):
# 第二重循环 剪枝
if nums[i] + nums[j] > target and nums[j] >= 0:
break
# 第二重循环 去重,需要注意是j>i+1而不是j>0,因为只需要和在此次循环中遍历过的j进行比较
if j > i+1 and nums[j] == nums[j-1]:
continue
# 双指针过程开始
left = j + 1
right = len(nums) - 1
while left < right:
sum = nums[i] + nums[j] + nums[left] + nums[right]
if sum > target:
right -= 1
elif sum < target:
left += 1
else:
res.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
return res