代码随想录算法训练营第六天(哈希表篇)|Leetcode484四数相加II,Leetcode383赎金信,Leetcode15三数之和,Leetcode18四数之和
Leetcode 484 四数相加II
题目链接: 四数相加II
给定四个长度均为n的数组,从四个数组中分别取一个数,使得四数之和为0,将这四个数组成一个元组。返回最终能够组成的元组的个数。
思路: 由于没有要求对元组进行去重,且四个数组之间相互独立,本题非常适合使用哈希表进行求解。将四个数组分为两组,nums1和nums2一组,nums3和nums4一组,先通过字典,记录从nums1和nums2中分别取元素时,元素和->出现次数的映射;随后再遍历nums3和nums4,从字典中找出对应元素和的出现次数,将其进行累加,即可得到最终结果
具体代码实现
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
count = 0
mydict = dict()
for i in range(len(nums1)):
for j in range(len(nums2)):
mydict[nums1[i]+nums2[j]] = mydict.get(nums1[i]+nums2[j], 0) + 1
for i in range(len(nums3)):
for j in range(len(nums4)):
count += mydict.get(-nums3[i]-nums4[j], 0)
return count
时间复杂度: O(n^2)
Leetcode 383 赎金信
题目链接: 赎金信
给定两个字符串ransomNote和magazine,判断ransomNote字符串是否能够通过magazine中的字母组成
思路: 记录ransomNote字符串中字母的出现次数和magazine中字母的出现次数,进行比较即可
具体代码实现
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
# 使用数组作为哈希表求解
if len(ransomNote) > len(magazine):
return False
hasharr = [0] * 26
for ch in ransomNote:
hasharr[ord(ch)-ord('a')] -= 1
for ch in magazine:
hasharr[ord(ch)-ord('a')] += 1
for i in hasharr:
if i < 0:
return False
return True
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
# 使用python计数器类求解
from collections import Counter
if Counter(ransomNote) <= Counter(magazine):
return True
return False
时间复杂度: O(n)
Leetcode 15 三数之和
题目链接: 三数之和
给定一个数组,从中取三个下标不相同的数,使得这三个数之和为0,并将这三个数保存为一个元组,返回所有这样的元组。
思路: 本题与先前四数之和II的主要不同之处在于: 1. 本题在一个数组中进行操作,而四数之和II在四个独立的数组中进行操作;2. 本题得到的数组需要去重,而四数之和II题目中不需要进行去重。为此,我们需要考虑如何进行去重。此题既可以通过双指针进行求解,在遍历的过程中进行去重;也可以仍然使用哈希表,同样在遍历过程中进行去重

具体代码实现
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 双指针法
result = []
nums = sorted(nums) # 首先对数组进行排序,方便后续处理时进行去重
for i in range(len(nums)):
# 由于数组元素从小到大进行排列,此时最小的数已经大于0,此后的情况一定不满足条件,直接剪枝
if nums[i] > 0:
return result
# 跳过已经处理过的元素
# 将当前元素与前一个元素进行对比,而不是将当前元素与后一个元素进行对比
# 如[-1, -1, 2, 3]这种情况,若使用后者进行去重,则会遗漏掉
if i>0 and nums[i] == nums[i-1]:
continue
left, right = i+1, len(nums)-1
while left<right:
if nums[i] + nums[left] + nums[right] < 0: # 小于目标值,移动左指针
left += 1
elif nums[i] + nums[left] + nums[right] > 0: # 大于目标值,移动右指针
right -= 1
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
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 哈希表法
# 在符合条件的三元组(a,b,c)中,b(存储) = 0-(a+c)(遍历)
nums = sorted(nums)
result = []
for i in range(len(nums)):
if nums[i] > 0:
return result
if i>0 and nums[i] == nums[i-1]:
continue
# 每处理完一个元素,初始化一个字典
mydict = dict()
for j in range(i+1, len(nums)):
if j>i+2 and nums[j] == nums[j-1] == nums[j-2]:
continue
cur = 0-(nums[i]+nums[j])
# 当cur在mydict中存在时,nums[j]为c
if cur in mydict:
result.append([nums[i], nums[j], cur])
mydict.pop(cur) # 弹出字典中对应键,避免重复
else: # 当cur在mydict中不存在时,nums[j]为b,将其进行记录
mydict[nums[j]] = 1
return result
时间复杂度: O(n^2)
Leetcode 18 四数之和
题目链接: 四数之和
给定一个数组,从中取出下标各不相同的四个数,使得这四个数的和等于目标和target,记录这四个数构成的元组,返回所有这样的元组
思路: 思路与三数之和类似,不同之处在于多一层循环,以及去重部分需要进行调整。

具体代码实现
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
# 双指针法
nums = sorted(nums)
result = []
for i in range(len(nums)):
if i > 0 and nums[i] == nums[i-1]:
continue
for j in range(i+1, len(nums)):
if j > i+1 and nums[j] == nums[j-1]:
continue
left, right = j+1, len(nums) - 1
while left < right:
if nums[i] + nums[j] + nums[left] + nums[right] > target:
right -= 1
elif nums[i] + nums[j] + nums[left] + nums[right] < target:
left += 1
else:
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
return result
时间复杂度: O(n^3)

浙公网安备 33010602011771号