题目 242. Valid Anagram
题目描述:
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1: 输入: s = "anagram", t = "nagaram" 输出: true
示例 2: 输入: s = "rat", t = "car" 输出: false
解题思路:
本题主要在于解决,判断两个词组是否由相同的字母组成。首先可以判断,两个词组不一样长的话就肯定不同, 然后在长度相同的情况下进行判断。如果用暴力解法,那么肯定会造成复杂度升高,所以才用hash表的方式解决。
首先创造一个长度为26,每个元素都为0的哈希表,代表26个字母出现的频次。当我们有一个词组,想要判断它在hash表中的各个字母出现频次的时候,采用ascall方法。在python中,ord('a')表示字母a的ascall码值,如果一个词组为“dog”,我们要找各个单词的频次的时候,利用
ord("d")-ord("a")得到字母d在哈希表中的index,然后将对应index的数值+1,字母d在hash表对应的值就加1.
回到本题,我们要判断两个词组是否相等,就不用分别创建两个hash表来比较了,在得到第一个词组的hash表的时候,将第二个词组直接在上面操作,不过区别在于对应频次减1,如果最后hash表全为0,那么这两个词组就是异位词。
代码:
注意⚠️
hash_0不能直接等于hash,因为实际上是将hash_0
设置为了对hash
列表的引用。这意味着hash_0
和hash
指向同一个列表对象,它们共享相同的内存空间。因此,当对hash
进行修改时,hash_0
也会同时受到影响。
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
#define a hashtable record
hash=[0]*26
hash_0=[0]*26
if len(s)!=len(t):
return False
else:
for i in s:
hash[ord(i)-ord("a")]+=1
for j in t:
hash[ord(j)-ord("a")]-=1
if hash==hash_0:
return True
else:
False
复杂度:
时间复杂度:
- 创建两个长度为26的哈希表,需要O(1)的时间复杂度。
- 检查两个词组的长度是否相等,需要O(1)的时间复杂度。
- 遍历第一个词组,对哈希表进行操作,需要O(n)的时间复杂度,其中n是第一个词组的长度。
- 遍历第二个词组,对哈希表进行操作,同样需要O(n)的时间复杂度。
- 比较哈希表是否全为0,需要O(1)的时间复杂度。
综上所述,代码的时间复杂度是O(n),其中n是词组的长度。
空间复杂度: 代码使用了两个长度为26的哈希表来记录字母的频次,因此需要额外的空间来存储这两个哈希表。哈希表的长度是固定的,所以空间复杂度是O(1)。
综上所述,代码的空间复杂度是O(1)。
题目 349. 两个数组的交集
题目描述:
给定两个数组,编写一个函数来计算它们的交集
解题思路:
本题在于求出两个集合相同的元素,而且结果必须是unique的。这道题采用hash set方法,先把第第一个list的hash set求出来,这种情况下所有元素都是unique的,然后查看第二个list中的元素是否在hash set中出现过,特别注意,在进行查询工作时, 以下代码的顺序不能错,如果写成for i in nums2 , if i in set_1,那么就违背了所有相交元素都是唯一的的限制。
for i in set_1:
if i in nums2:
res.append(i)
代码:
创建set直接用set(nums),不用写个for循环。
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
#hashtable(list,map,set),元素出现
#如果数值很大就不用list,浪费存储空间,本题用set(python dict)
#generate a hashtable for nums1
set_1 = set(nums1)
res = []
#found element in nums2 in nums1_dict or not
for i in set_1:
if i in nums2:
res.append(i)
return res
复杂度:
时间复杂度:
- 创建哈希集合
set_1
,需要将nums1
中的元素逐个添加到集合中,这需要 O(n1) 的时间复杂度,其中 n1 是nums1
的长度。 - 遍历
set_1
,对其中的元素进行查询操作,检查其是否存在于nums2
中,这需要 O(n2) 的时间复杂度,其中 n2 是nums2
的长度。
综上所述,代码的时间复杂度是 O(n1 + n2),其中 n1 是 nums1
的长度,n2 是 nums2
的长度。
空间复杂度:
- 创建了一个哈希集合
set_1
来存储nums1
中的元素,这需要 O(n1) 的空间复杂度,其中 n1 是nums1
的长度。 - 创建了一个结果列表
res
来存储相交的元素,其最大长度不会超过nums1
和nums2
的长度的较小值。因此,结果列表的空间复杂度为 O(min(n1, n2))。
题目 202. Happy Number
题目描述:
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
解题思路:
本题在于一直求解各个数字的平方和是否有1出现,如果没有说明进入一个循环了。让我们知道出现一和是否进入循环就用hashtable,但在这之前我们要写一个function用来计算一个数的各位平方和,,字符串方法和算术方法。虽然字符串方法可能更直观,但算术方法在性能上可能更优,因为它避免了数字和字符串之间的转换。
def getSumOfSquares(num):
total_sum = 0
while num > 0:
#求解个位数
digit = num % 10
total_sum += digit * digit
#求解除了个位数之外的数
num //= 10
return total_sum
比如说135, 135%10=5,135//=10:13, 13%10=3,13//=10:1
然后,我们使用一个哈希集合(hash set)来跟踪我们已经见过的数字。在每次迭代中,我们都计算n的各位数字的平方和,并检查这个结果是否为1(表示n是一个快乐数)或者这个结果是否已经在我们的哈希集合中(表示我们已经进入了一个循环)。如果满足这两个条件中的任何一个,我们就退出循环。
最后,当我们退出循环时,我们检查n是否等于1。如果是,那么我们知道n是一个快乐数,函数返回真(true)。如果不是,那么我们知道n不是一个快乐数,因为我们已经进入了一个不包含1的循环,函数返回假(false)。
seen = set()
while n != 1 and n not in seen:
seen.add(n)
n = getSumOfSquares(n)
return n == 1
代码:
解法一:
class Solution:
def isHappy(self, n: int) -> bool:
# Define a helper function to get the sum of the squares of the digits of a number
def getSumOfSquares(num):
total_sum = 0
while num > 0:
#求解个位数
digit = num % 10
total_sum += digit * digit
#求解除了个位数之外的数
num //= 10
return total_sum
# Use a set to store the sums we have already calculated
seen = set()
while n != 1 and n not in seen:
# If the number is not 1 and we have not seen it before, add it to the set
seen.add(n)
# Get the sum of the squares of the digits
n = getSumOfSquares(n)
# If we end with 1, then n is a happy number
return n == 1
解法二:
class Solution:
def isHappy(self, n: int) -> bool:
def getSumOfSquares(n):
sum = 0
# Convert the number to a string to iterate over its digits
n = str(n)
for digit in n:
# Convert the digit back to an integer and add its square to the sum
sum += int(digit)**2
return sum
# Use a list to keep track of the sums we have already seen
hash_list = []
while True:
n = getSumOfSquares(n)
if n == 1:
# If the sum is 1, the number is happy
return True
elif n in hash_list:
# If the sum is in our list, we have entered a cycle, so the number is not happy
return False
else:
# If the sum is new, add it to our list and continue the loop
hash_list.append(n)
# This line is unnecessary because the function always returns before reaching it
#return False
复杂度:
-
时间复杂度:O(log n)
这个算法的时间复杂度可能并不直观。虽然我们在循环中进行了多次计算,但每次计算都会让数字n变小。因此,我们可以认为时间复杂度是O(log n)。这是一个很宽松的上界,实际的时间复杂度可能更低,因为我们通常很快就会达到1或者进入一个循环。
-
空间复杂度:O(log n)
我们用一个集合来保存已经计算过的数字的平方和。在最坏的情况下,我们可能需要保存所有这些数字,因此空间复杂度是O(log n)。这是因为每次计算都会使数字n变小,所以我们最多需要log n步才能达到1或者进入一个循环。
题目:
1. Two Sum
题目描述:
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
解题思路:
本题要找两个数字想加起来等于target,并且返回各自的下标。如果我们用暴力解法写两层for循环,那么就会有O(n^2)的复杂度,所以采用hash map的方法,找寻这个map里面是否存在target-val, 最开始的时候虽然hash map是空的,但是不能直接往里面加元素,需要直接先写决定条件,
如果我们先把 val
添加到哈希表中,那么在 val
等于 target - val
的情况下,我们就无法正确判断出这是满足条件的一个解。
举个例子,假设我们的 target
是 6,现在遍历到的 val
是 3,且这是数组中的第一个元素。此时 target - val
也是 3,如果我们在判断条件之前先把 val
添加到哈希表中,那么在执行判断条件 if target - val in hash.keys():
时,会发现 target - val
已经在哈希表中,从而错误地认为我们找到了一个解,其实并没有。
所以,为了避免这种情况,我们需要先写判断条件,如果 target - val
在哈希表中,就返回对应的索引,否则再把 val
添加到哈希表中。这样就能保证我们的算法能正确地找到满足条件的两个数。
if target-val in hash.keys():
return [hash[ target-val],index]
else:
hash[val]=index
代码:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
#hash map
hash={}
#查找target-val是否在hash中出现过,如果有则返回
for index,val in enumerate(nums):
if target-val in hash.keys():
return [hash[ target-val],index]
else:
hash[val]=index
复杂度:
- 时间复杂度:O(n)
这个算法只需要遍历一次数组。因为哈希表(在 Python 中为字典)的查找操作的平均时间复杂度接近 O(1),因此总的时间复杂度为 O(n)。
- 空间复杂度:O(n)
这个算法使用了一个哈希表来保存数组中的元素和对应的索引。在最坏的情况下,数组中的每个元素都会被存入哈希表,因此空间复杂度为 O(n)。
注意:尽管哈希表的查找操作的平均时间复杂度是 O(1),但在极端情况下(所有元素都哈希到同一个位置)可能会退化为 O(n)。然而,这种情况在实践中几乎不会发生,所以我们通常认为哈希表的查找操作的时间复杂度是 O(1)。