1.两数之和-哈希表
思路:需要判断一个元素是否遍历过,是否在集合中出现过,用到哈希表的结构
- 为什么会想到用哈希表:需要判断需要的值是否在之前遍历过的元素中出现过
- 哈希表为什么用map:因为要判断值是否出现过,同时返回对应元素的下标
- 本题map是用来存什么的:存放已经遍历过数据的值和下标
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
dic = {}
# 通过建立数组得到对应遍历过的元素的值
for i in range(len(nums)):
y = target - nums[i]
if y in dic.keys():
return [i,dic[y]]
else:
dic[nums[i]] = i
454.四数相加-哈希表
题目简介: 给定四个长度相同的数组,在四个数组中分别找一个元素,使得四个元素相加等于0,找到这样取值的数量有多少。
整体思路: 暴力解法是遍历四个数组,然后count++,**另一种思路是仅遍历A+B两个数组,然后看C+D中有没有出现对应的值。**两数相加的变形,将两个数组当成整体进行两数相加。
class Solution:
def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
map = {}
for a in nums1:
for b in nums2:
if a+b not in map.keys():
map[a+b] = 1
else:
map[a+b] += 1
# if the -(a+b) exists in nums3 and nums4, we shall add the count
count = 0
for c in nums3:
for d in nums4:
if -(c+d) in map.keys():
count += map[-(c+d)]
return count
383.赎金信-哈希表+字典
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
map = {}
for i in magazine:
if i not in map.keys():
map[i] = 1
else :
map[i] += 1
for j in ransomNote:
if j not in map.keys():
return False
elif j in map.keys() and map[j] == 0:
return False
else:
map[j] -= 1
return True
# 利用数组哈希表结构
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
arr = [0] * 26
for x in magazine: # 记录 magazine里各个字符出现次数
arr[ord(x) - ord('a')] += 1
for x in ransomNote: # 在arr里对应的字符个数做--操作
if arr[ord(x) - ord('a')] == 0: # 如果没有出现过直接返回
return False
else:
arr[ord(x) - ord('a')] -= 1
return True
15.三数之和-排序+双指针
思路:
- 排序:因为不需要获取下标的值,所以可以先对这个数组进行排序
- 双指针:根据当前值的大小变更指针的指向,本题目不需要返回数组的下标,所以可以使用双指针的方法进行求解。
- 去重:a+b+c = 0 ,如何对a,b,c进行去重。
nums[i] = nums[i-1]按照这个条件进行剪枝操作,同时还需要对left和right的位置进行剪枝操作。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
nums.sort()
result = []
for i in range(n):
# 对第一个数进行剪枝
if i>0 and nums[i] == nums[i-1]:
continue
# 如果第一个元素已经大于0,那么没有必要继续寻找
if nums[i] > 0:
break
left = i+1
right = n-1
while right > left:
total = nums[i] + nums[left] + nums[right]
if total == 0:
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
elif total > 0:
right -= 1
else:
left += 1
return result
反思:
4. 临界条件思考不清晰: 没有想到当第一个元素移动到大于0的位置,即nums[i]>0时,可以直接停止搜索。
5. 后续left和right指针剪枝的位置,没有写对, 应该是在找到一个元素之后进行剪枝,这样可以做到用尽可能少的时间达到剪枝的作用。
6. 第一层剪枝操作: 第一层剪枝nums[i]==nums[i+1]用来判断结果集中有没有重复元素,而nums[i]==nums[i-1]是用来判断result中的列表去重。
18.四数之和-双指针+剪枝
- 双层for循环,双指针的方式,即在三数之和的基础上在外面套一个循环
- 细节:重点在k,i的剪枝以及后续left和right的去重
- 注意:不能延续三数之和的剪枝操作,因为输入的target既可为正数,也可为负数。
四数之和的双指针解法是两层for循环nums[k] + nums[i]为确定值,依然是循环内有left和right下标作为双指针,找出nums[k] + nums[i] + nums[left] + nums[right] == target的情况,通过双指针的方式可以使时间复杂度与原来相比降低一个量级。
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
n = len(nums)
nums.sort()
result = []
for k in range(n):
# 第一层剪枝操作
if k > 0 and nums[k] == nums[k-1]:
continue
for i in range(k+1,n-2):
if i > k+1 and nums[i] == nums[i-1]:
continue
left = i+1
right = n-1
while left < right:
value = nums[k]+nums[i]+nums[left]+nums[right]
if value > target:
right -= 1
elif value < target:
left += 1
else:
result.append([nums[k],nums[i],nums[left],nums[right]])
# 三层剪枝
while left < right and nums[right] == nums[right-1]:right-= 1
while left < right and nums[left] == nums[left+1]:left+= 1
right -= 1
left += 1
return result