242.有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1: 输入: s = "anagram", t = "nagaram" 输出: true
示例 2: 输入: s = "rat", t = "car" 输出: false
说明: 你可以假设字符串只包含小写字母。
首先排除暴力法,思路太简单不多赘述。
思路首先想到哈希,对应字母出现一次,则对应的哈希表位置+=1,由于本次题目限制在了小写字母,所以取值范围就是1-26,范围确定可以使用数组,如果不确定数的范围,无法使用数组,而是需要使用set,本题使用数组。
由于用数组需要用到数字,小写字母对应数组我们可以想到ASCII码,每个字母的ASCII码减去‘a’的ASCII码恰好就是英文字母表的对应顺序,一一对应。
代码实现如下:
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
# 确认范围是'a'到'z',使用数组
nums = [0] * 26
for i in s:
nums[ord(i)-ord('a')] += 1
for i in t:
nums[ord(i)-ord('a')] -= 1
for i in range(26):
if nums[i] != 0:
return False
return True
另外记录defaultdict和counter的用法,代码随想录提供的代码如下:
defaultdict
defaultdict 是 dict 的一个子类,它提供了一个默认值的机制,当访问字典中不存在的键时,会自动创建该键,并将其值设置为默认值。
Counter
Counter 是一个字典子类,用于计数可哈希对象。它是一个集合,元素的数目由字典的值给出。
总结
- defaultdict 允许你为字典中不存在的键提供一个默认值。
- Counter 是一个专门用于计数的字典,它提供了方便的方法来添加和更新计数。
Python写法二(没有使用数组作为哈希表,只是介绍defaultdict这样一种解题思路):
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
from collections import defaultdict
s_dict = defaultdict(int)
t_dict = defaultdict(int)
for x in s:
s_dict[x] += 1
for x in t:
t_dict[x] += 1
return s_dict == t_dict
Python写法三(没有使用数组作为哈希表,只是介绍Counter这种更方便的解题思路):
class Solution(object):
def isAnagram(self, s: str, t: str) -> bool:
from collections import Counter
a_count = Counter(s)
b_count = Counter(t)
return a_count == b_count
349. 两个数组的交集
题意:给定两个数组,编写一个函数来计算它们的交集。
说明: 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序。
思路很明确,只是不熟悉python提供的几个集合类用法,具体思路就是判断数组2里的数字是否在数组1中出现过,如果出现过就存储在result数组中,同时确保相同数字在result数组中只出现一次,如果判断在result数组中已有,则不存入。
代码实现如下:
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
#num = set() # 后面发现使用set好像有点多余,去掉了依然通过
result = []
#for i in nums1:
# num.add(i)
for i in nums2:
if i in nums1 and i not in result:
result.append(i)
return result
使用字典和集合的方法如下,顺便学习一下字典和集合的用法:
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
# 使用哈希表存储一个数组中的所有元素
table = {}
for num in nums1:
table[num] = table.get(num, 0) + 1
# 使用集合存储结果
res = set()
for num in nums2:
if num in table:
res.add(num)
del table[num]
return list(res)
- 创建哈希表:首先,代码通过一个循环遍历 nums1 数组,使用一个字典 table 来存储 nums1 中的每个元素及其出现的次数。这里使用 table.get(num, 0) 来获取字典中 num 的当前值,如果 num 不在字典中,则返回默认值 0。然后将这个值加一,表示 num 出现了一次。
- 初始化结果集合:使用一个集合 res 来存储最终的交集结果。集合自动去重,因此如果 nums1 和 nums2 中有重复的元素,它们在结果中也只会被计算一次。
- 遍历第二个数组:代码通过另一个循环遍历 nums2 数组。对于 nums2 中的每个元素 num,如果它存在于 table 字典中(即 num 也在 nums1 中),则将其添加到结果集合 res 中,并从 table 中删除该元素。这样做是为了确保每个元素在结果中只出现一次,即使它在 nums1 中出现多次。
- 返回结果:最后,将结果集合 res 转换回列表,并返回这个列表。
这段代码的效率相对较高,因为它只需要遍历两个数组各一次,并且使用哈希表和集合的查找和插入操作的时间复杂度通常是 O(1)。因此,整个算法的时间复杂度是 O(n + m),其中 n 和 m 分别是 nums1 和 nums2 的长度。
使用数组的方法在此忽略了,另外再学习一下集合的用法,使用set1&set2方法取交集,使得代码十分精简:
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
return list(set(nums1) & set(nums2))
- 转换为集合:首先,将 nums1 和 nums2 转换为集合 set(nums1) 和 set(nums2)。集合是一个无序的不重复元素集,自动去除了数组中的重复元素。
- 集合交集操作:使用 & 运算符来获取两个集合的交集。在Python中,& 运算符用于计算两个集合的交集,即同时存在于两个集合中的元素。
- 返回结果:最后,将得到的交集集合转换回列表,并返回这个列表。
这段代码的优点是简洁易读,且利用了Python的集合操作,使得代码更加直观。其时间复杂度主要由集合的创建和交集操作决定,通常也是 O(n + m),其中 n 和 m 分别是 nums1 和 nums2 的长度。
第202题. 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
这道题思路为:首先判断数字是否为1,为1直接返回True。
其次直接进入循环,对每一位都进行平方加和处理,只要得到的结果res不为1就循环执行,问题在于这个过程有可能会无限循环下去,因为res可能永远不等于1,这说明res有可能会重复出现得到同样的数字,所以需要一个集合set来记录出现过的res,当出现重复res的时候肯定能够判断不是快乐数,此时直接返回False
这道题思路挺早想出来,但是程序实现上一直卡bug,问题就在于对数字的处理不是特别的熟练,应该学会用函数单独分出来处理会有助于处理过程。同时在代码中,忘记了python中/10是不会向下取整的,是得到一个浮点数。
如果你想要进行向下取整或向上取整,可以使用以下方法:
- 向下取整:可以使用 // 运算符,它执行的是整数除法,结果总是向下取整到最接近的整数。
python
result = 9 // 10
print(result) # 输出: 0
- 向上取整:Python没有内置的向上取整运算符,但可以通过一些方法实现。一个常用的方法是将除法结果加上一个特定的值后再进行向下取整。
python复制
result = (9 + 9) // 10
print(result) # 输出: 1
因此要结束循环应该是使用//10或者设置循环条件为>1
代码实现如下:
class Solution:
def isHappy(self, n: int) -> bool:
if n == 1:
return True
else:
new_n = n
mark = set()
while new_n != 1:
res = 0
while new_n > 0:
res += (new_n%10)**2
#new_n = new_n / 10
new_n = new_n // 10 # 这里需要注意用//10来向下取整,不然会死循环
if res == 1:
return True
else:
if res in mark:
return False
else:
mark.add(res)
new_n = res
在处理各位数平方和的时候可以考虑使用以下函数
divmod(a, b)
参数
- a:被除数。
- b:除数。
返回值
- 返回一个包含两个元素的元组 (quotient, remainder),其中 quotient 是商,remainder 是余数。
另外记录学习其他代码实现方式:
最直接的思路,直接复述题目的计算过程,方法是先转换为str,然后再对每一位转换为int进行运算:
class Solution:
def isHappy(self, n: int) -> bool:
record = set()
while n not in record:
record.add(n)
new_num = 0
n_str = str(n)
for i in n_str:
new_num+=int(i)**2
if new_num==1: return True
else: n = new_num
return False
集合+精简:
class Solution:
def isHappy(self, n: int) -> bool:
seen = set()
while n != 1:
n = sum(int(i) ** 2 for i in str(n))
if n in seen:
return False
seen.add(n)
return True
1. 两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
最直接的思路,暴力法复杂度肯定是n²,直接排除。
自己的思路:由于是两数加和等于target,所以确定了第一个数n1的时候,n2的具体数值其实已经确定是target-n1,所以我只需要在剩下的数组元素中寻找是否存在n2即可,如果没有就令n1等于下个数字重复以上过程。(一开始以为只需要输出两个数,但后面才发现需要输出的是两个下标,所以时间非常长,实现的应该不对。后来其实想到要用字典实现,但因为字典用法还是不熟悉,感觉把时间浪费在不熟悉没怎么用过的地方没啥意义,就直接看规范代码了)
代码实现如下:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
length = len(nums)
for i in range(length):
n1 = nums[i]
n2 = target-n1
j = i+1
while j<length:
if nums[j] == n2:
return [i, j]
else:
j += 1
return None
使用字典:我一开始的疑惑在于相同元素加和的时候,另外一个元素匹配到自己的话怎么办,没想到可以把遍历过的元素再放进字典中,这样第一次匹配到后面那个元素的时候,就必然会匹配到前面的那个元素,这个思路对自己很有启发。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
records = dict()
for index, value in enumerate(nums):
if target - value in records: # 遍历当前元素,并在map中寻找是否有匹配的key
return [records[target- value], index]
records[value] = index # 如果没找到匹配对,就把访问过的元素和下标加入到map中
return []
在Python中,enumerate() 是一个内置函数,用于将一个可迭代对象(如列表、元组、字符串等)组合为一个索引序列,同时列出数据和数据下标。这使得在遍历可迭代对象时,可以同时获取到元素的索引和值。
语法
python
enumerate(iterable, start=0)
参数
- iterable:一个可迭代对象,如列表、元组、字符串等。
- start(可选):计数开始的索引,默认为0。如果指定了 start 参数,那么索引将从这个值开始。
返回值
enumerate() 返回一个枚举对象,该对象可以被用来创建索引序列。通常,我们使用循环来遍历这个枚举对象。
所以for index, value in enumerate(nums):可以返回对应的index和value
使用集合:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
#创建一个集合来存储我们目前看到的数字
seen = set()
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [nums.index(complement), i]
seen.add(num)