目录
LeetCode242. 有效的字母异位词
链接:242. 有效的字母异位词 - 力扣(LeetCode)
核心点:感受到 数组 用来做哈希表 给我们带来的便利。
先看暴力的解法,两层for循环,同时还要记录字符是否重复出现,很明显时间复杂度是 O(n^2)。
暴力的方法这里就不做介绍了,直接看一下有没有更优的方式。
方法:数组作哈希表
1. 思路
先看暴力的解法,两层for循环,同时还要记录字符是否重复出现,很明显时间复杂度是 O(n^2)。
暴力的方法这里就不做介绍了,直接看一下有没有更优的方式。
数组其实就是一个简单哈希表,而且这道题目中字符串只有小写字符,那么就可以定义一个数组,来记录字符串s里字符出现的次数。
需要定义一个多大的数组呢,定一个数组叫做record,大小为26 就可以了,初始化为0,因为字符a到字符z的ASCII也是26个连续的数值。
Example:为了方便举例,判断一下字符串s= "aee", t = "eae"。
定义一个数组叫做record用来上记录字符串s里字符出现的次数。
需要把字符映射到数组也就是哈希表的索引下标上,因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。
再遍历 字符串s的时候,只需要将 s[i] - ‘a’ 所在的元素做+1 操作即可,并不需要记住字符a的ASCII,只要求出一个相对数值就可以了。 这样就将字符串s中字符出现的次数,统计出来了。
那看一下如何检查字符串t中是否出现了这些字符,同样在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。
那么最后检查一下,record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false。
最后如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。
2. 代码实现
class Solution(object):
def isAnagram(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
# 数组作哈希表,记录元素出现的频率
record = [0]*26
# 遍历字符串S,在每个对应位置上+1
for item in s:
index = ord(item) - ord("a")
record[index] += 1
# 遍历字符串T,在每个对应位置上-1
for item in t:
index = ord(item) - ord("a")
record[index] -= 1
# 看看最后的哈希表是不是元素全为0
for i in range(0,26):
if record[i] != 0:
return False
return True
3. 复杂度分析
因为要分别遍历长度为N的字符串s和t,所以时间复杂度为O(n),空间上因为定义是的一个常量大小的辅助数组,所以空间复杂度为O(1)。
4. 思考
(1)常用的三种哈希表有数组、set和map,当哈希表比较小并且范围确定的时候,用数组;当哈希表范围比较大而且不确定的时候,用set;当有key-value的映射关系的时候,用map。
(2)在C++ 中,直接用字母减字母的话,编译器会自动用字母的ASCII码计算,但是在Python中要用ord(“a”),我们并不用搞清楚ASCII码究竟是多少,只用知道这26个字母是连续的,然后减去”a”的ASCII码,算出一个相对位置就可以了。
(3)还有另一种做法是,把两个字符串分别用两个数组统计,然后再比较两个数组是否一样。
(4)这道题是数组在Hash Map中的经典应用。
(5)思考:我们遇到要快速判断元素是否出现在集合里的时候,要考虑哈希法。
(6)数组就是简单的哈希表,但是数组的大小可不是无限开辟的。
本题学习时间:55分钟
Leetcode349. 两个数组的交集
链接: 349. 两个数组的交集 - 力扣(LeetCode)
这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。
思考:
当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
方法一:用Set作HashMap
1. 思路
本题其实是使用set的好题,但是后来力扣改了题目描述和 测试用例,添加了 0 <= nums1[i], nums2[i] <= 1000 条件,所以使用数组也可以了,我们可以先忽略这个条件,尝试去用set解决这道题目。
数据结构的选择?要不要用数组作为Hash table?为什么要用set作哈希表?
用数组来做哈希表是不错的选择,例如,前一道题:有效的字母异位词
但是要注意,使用数组来做哈希的题目,是因为题目都限制了数值的大小。
而这道题目没有限制数值的大小,就无法使用数组来做哈希表了。
而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。所以我们打算选择set。
用set的思路如下:
- 首先,定义一个set哈希表,称为result,存放之后要返回的结果,之所以用set是因为它可以在insert元素的时候就自动去重;
- 把nums1中的元素放进另一个set哈希表中(会做去重操作),定义为num1_set;
- 遍历nums2中的元素,然后再nums1_set这个哈希表中找有没有出现,如果找到了的话,就把它存到result中去;
- 遍历结束之后,将result转换为list返回
2. 代码实现
# 把set用作hashMap
# time:O(N);space:O(N)
class Solution(object):
def intersection(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: List[int]
"""
# 保存结果的result初始化
result = set()
# 将nums1中的元素存入set中
nums1_set = set(nums1)
# 遍历nums2,和nums1_set比较,如果存在,就加进result
for item in nums2:
if item in nums1_set:
result.add(item)
return list(result)
3. 复杂度分析
时间复杂度和空间复杂度都是O(N)。
将nums1中的元素存入set数据结构中,就是O(N)的时间复杂度,然后遍历num2中的元素一个个比较,又是O(N)的时间复杂度,最后把result转换成list,也是O(N)的时间复杂度,所以总体来说time complexity = O(N);空间上创建了两个set和一个list,长度都是O(N)数量级的,所以space complexity = O(N)。