题一:242. 有效的字母异位词
链接
视频总结
关键点
编程思路
Me:
- 第一遍遍历确定s中每个字母出现的次数
- 第二次遍历在哈希表中减去t里出现的字母
- 遍历一遍哈希表,全为零说明一样,否则不满足
卡尔:
- 计数只需找到每个字母相对于a的距离,因为26个字母的ASCII码是连续的,所以用ord函数找到字母的ascii码值减去a的ascii码值就可以确定每个字母应存放在数组里的索引
力扣实战
思路一:
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
hashtable = [0]*26
for i in s:
hashtable[ord(i)-ord("a")] += 1 #ord()函数以一个字符(长度为1的字符串)作为参数,返回对应的 ASCII 数值,或者 Unicode 数值
for j in t:
hashtable[ord(j)-ord("a")] -= 1
for i in range(len(hashtable)):
if hashtable[i]:
return False
return True
# 反思1:
文档总结
1. #ord()函数以一个字符(长度为1的字符串)作为参数,返回对应的 ASCII 数值,或者 Unicode 数值
题二:349. 两个数组的交集(easy)
链接
视频总结
关键点
- 本题在数的大小确定为一千以内之后,可以使用数组来实现哈希表。否则需要判断用数组、set还是map
- 当数太大之后,采用数组会浪费很多空间,而使用set一个个加入则省空间。数值很分散时也不适合用数组
- 使用哈希表原因:哈希表最擅长判断一个元素是否在一个集合里出现过
编程思路
Me:
数组法:
- 对数组1遍历,若索引处值为1不变,为零则加一
- 对数组2遍历,若索引处值为1则加一,否则不变
- 遍历数组,若值为2,把索引加入数组,最后返回数组
卡尔:
- 第一步还是一样,第二部若为一则直接加入数组,则不需要遍历三次
- 编程时无需用if语句,直接令所有索引处为1
字典法:
- 通过字典实现哈希表,思路还是一致,但是用的空间是不是相对变少?因为可以做离散的空间,而不是像数组那样做连续的空间。
力扣实战
思路一:
class Solution: #easy
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
hashtable = [0]*1000
result = []
for i in nums1:
if hashtable[i] == 0: # hashtable[i] = 1
hashtable[i] += 1
for i in nums2:
if hashtable[i] == 1: # 等于一就说明已经出现过,则可以直接放进result里,而无需加一,然后再遍历一次
hashtable[i] += 1
for i in range(1000):
if hashtable[i] == 2:
result.append(i)
return result
# 反思1:
思路二:
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
dict = {}
ans = []
for num in nums1:
dict[num] = 1
for num in nums2:
if num in dict.keys() and dict[num] == 1: # 必须加and后面的和+=1,否则输出的结果可能会有重复
ans.append(num)
dict[num]+=1 # 或者直接令成非1 的数字
return ans
文档总结
1.
题三:202. 快乐数(无视频)
链接
编程思路
Me:
无思路
卡尔:
- 从无限循环切入,无限循环说明出现了相同的计算结果,这一点很关键
- 先定义一个每一步计算的函数
- 然后执行计算,计算的结果若为1则成功,如果不为一,则保存到一个数组中,同时若计算的结果在这个数组里说明出现来循环,则不是快乐数。
力扣实战
思路一:
class Solution:
def isHappy(self, n: int) -> bool:
def cal_func(n):
sum = 0
while n:
sum += (n % 10)**2 # n的个位数的平方 %返回除法的余数
n = n//10 # n 去掉个位数 //向下取接近商的整数
return sum
record = [] # 也可以使用set()函数来做,是不是就相当于cpp的set数据结构
while True: # 思考:这一行的意思是如果while后面的条件是true时,执行循环,而调节本身就是true,所以下面一定会执行,而且若是没有退出会一直执行下去
n = cal_func(n)
if n == 1:
return True
elif n in record:
return False
else:
record.append(n)
# 反思1:
题四:1. 两数之和
链接
视频总结
关键点
- 当需要判断这个元素是否出现过,首要思路应该就是哈希表
- 进一步分析发现需要存储的对象有数值及其下标,于是在cpp需要用到map这个函数,在python里面是字典
- 同时,我们需要查询t-n是否出现,也就是查询字典的key,故使用key存储值;最终需要获得数的下标,所以value用来储存下标。
编程思路
Me:
- 可以转化为target-num是否在数组中,即哈希表
- 进一步分析,数字的大小为10的九次方使用数组则浪费太大空间,考虑使用字典实现
- 建立空字典,下标作为key,数字为value,
- 数组长度for循环遍历,Target - num在字典中且key不等于i 则返回索引,
- 至于答案里的索引不同,可通过for循环起点来控制
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
hash = dict()
for i,num in enumerate(nums):
hash[i] = num
for i in range(len(nums)):
for j in range(i+1,len(nums)):
if target-nums[i] == hash[j]:
return [i,j]
反思:最终的代码形式上和暴力法的两个for循环没什么区别,还浪费了大量空间。分析:先建立链表再查找会遇到哈希冲突的问题,但是若是一边遍历一边建立哈希表则不会。
步骤:
- 对于每一个num和它的index,若target-num在dict的key里面,那么value对应的就是我们要找的另一个索引,若不在,num作为key,index作为值加入字典,此时即使哈希冲突,那么冲突的那一对数字一定不是我们的目标,可以任意举例。索引此处其实不是在建立一个哈希表,因为无所谓是否冲突,而是使用哈希表和字典储存数据的思想来解决问题
卡尔:
力扣实战
思路一:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
hashtable = {}
for i,num in enumerate(nums):
if target-num in hashtable:
return [hashtable[target-num],i]
hashtable[num] = i#这句不能放在if语句之前,解决list中有重复值或target-num=num的情况
# 反思1: