哈希表理论基础
一般哈希表都是用来快速判断一个元素是否出现集合里;PS:基于哈希表的查询操作的时间复杂度为O(1)
常见的三种哈希结构:
- 数组
- set(集合)
- map(映射)
用哈希表解题最重要的是要考虑用哪种哈希结构
有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。(s和t仅包含小写字母)注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
解题的核心思想就是要想直到两个字符串是否为字母异位词,即统计两个字符串的字母出现次数,判断是否相等。
由题目可知,字符串的构成均为小写字母,那么即统计26个小写字母的出现次数。对于这种元素在有限范围的,一般选用数组结构的哈希表。由于小写字母的ASCII码是连续的,那么如果a作为数组第一个元素,以此类推某个字母与a字母的ASCII码差值即为数组索引,对应的数组元素为该字母出现的次数。
首先,定义一个长度为26的数组结构的哈希表,遍历第一个字符串,得到对应的哈希表,其中元素为这个字符串中每个字母出现的次数;接着遍历另一个字符串,每出现一次某个字母,将哈希表对应的元素减一,直到遍历完整个字符串。最后,判断哈希表的每个元素是否均为0,只要有一个元素不为0则这两个字符串不为字母异位词。
class Solution(object):
def isAnagram(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
hash_table = [0]*26
for i in range(len(s)):
hash_table[ord(s[i])-ord('a')] += 1 #ord()计算字符对应的ASCII码
for j in range(len(t)):
hash_table[ord(t[j])-ord('a')] -= 1
for m in hash_table:
if m != 0:
return False
return True
两个数组的交集
给定两个数组 nums1 和 nums2 ,返回它们的交集。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序。
交集为即在nums1中出现又在nums2中的元素,且输出的每个元素唯一。那么,只能用集合结构的哈希表或者映射结构的哈希表(python中就是字典),利用集合元素不重复或字典key不重复的特性。
遍历一个数组得到集合或者字典类型的哈希表,再遍历另外一个数组,判断元素是否在哈希表内,在的话放入输出的集合中,并移除哈希表对应的元素;不在则继续遍历下一个元素。最后,将集合转换为列表得到最终输出。
class Solution(object):
def intersection(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: List[int]
"""
# 集合
hash_table = set()
for n1 in nums1:
hash_table.add(n1)
# 字典
#hash_table = {}
#for n1 in nums1:
# hash_table[n1] = hash_table.get(n1,0) + 1 #dict.get(key,x)表示返回key对应的value,key不存在则返回x
result = set()
for n2 in nums2:
if n2 in hash_table:
result.add(n2)
hash_table.remove(n2)
return list(result)
还有一种解法直接将两个数组转换集合,再按位与&得到交集。
class Solution(object):
def intersection(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: List[int]
"""
return list(set(nums1) & set(nums2))
这里有一个地方就是只能用&操作而不能用and操作,and是逻辑与运算。
a = (1,2,3,4)
b = (1,2,3,4,5)
a & b # (1,2,3,4)
a and b # (1,2,3,4,5)
快乐数
判断一个数 n 是不是快乐数。 「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。 如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
本题有两个难点,一是计算该数字的每个位置上数字的平方和sum,二是该数字不为快乐数的判断条件。按题意可知,某个数为快乐数为循环若干次得到的sum为1,那么不为快乐数则为在循环过程中得到的sum在之前出现过,也就是说陷入了死循环,则表示该数字不是快乐数。
class Solution(object):
def isHappy(self, n):
"""
:type n: int
:rtype: bool
"""
hash_table = set()
while True:
n = self.get_num(n)
if n == 1:
return True
if n in hash_table:
return False
hash_table.add(n)
def get_num(self, n):
s = 0
while n:
n , r = divmod(n, 10) # 159 , 8 = divmod(1598, 10)
s += r ** 2
return s
两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个
整数,并返回它们的数组下标。可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。可以按任意顺序返回答案。
需要知道一个数组中是否存在两个元素相加等于某个值target,可以转换为遍历这个数组并把遍历过的元素存进哈希表,每往后遍历查询一次是否存在一个遍历过的元素使得两者之和为target。如果存在则返回遍历的那个元素对应的索引,不存在则把当前遍历的元素存进哈希表(如果该元素已存在则会覆盖,索引更新为该元素再次出现的索引)。然后,哈希表除了记录元素之外,还需要把元素对应的索引存进哈希表与其一一对应。所以,自然而然,我们应该选取映射结构的哈希表。
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
hash_table = {}
for i in range(len(nums)):
n = target - nums[i]
if n in hash_table: #判断当前所需要的另一数字是否出现过
return [hash_table[n],i]
hash_table[nums[i]] = i
return []
今天的题目好多,完事状态也不是很好,陆陆续续感觉今天也没干啥就只刷了题和写博客了。明天合理安排,还要弄小论文呢。好想摆~~~