哈希表
哈希表通过一个哈希函数将键(Key)映射到表中一个位置,这个位置就是该键的值(Value)的存储位置。在许多应用中都非常有用,比如数据库索引、缓存实现、快速查找等。 哈希函数最好能尽量简单地实现定义域必须包括需要存储的全部关键码,计算的地址均匀分布在整个空间中。 常用的构造哈希函数的方法有:
1.直接定制法
哈希函数为关键字的线性函数如 H(key)=a*key+b。
2.数字分析法
假设关键字集合中的每个关键字key都是由s位数字组成,分析key中的全体数据,并从中提取分布均匀的若干位或他们的组合构成全体。
3.平方取中法
如果关键字的每一位都有某些数字重复出现频率很高的现象,可以先求关键字的平方值,通过平方扩大差异,而后取中间数位作为最终存储地址。
4.折叠法
如果数字的位数很多,可以将数字分割为几个部分,取他们的叠加和作为hash地址 。
5.除留余数法
H(key)=key MOD p (p<=m m为表长)。
第一题:找单独的数
问题描述
在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。
要求:
- 设计一个算法,使其时间复杂度为 O(n),其中 n 是班级的人数。
- 尽量减少额外空间的使用,以体现你的算法优化能力。
测试样例
样例1:
输入:
cards = [1, 1, 2, 2, 3, 3, 4, 5, 5]
输出:4
解释:拿到数字 4 的同学是唯一一个没有配对的。
样例2:
输入:
cards = [0, 1, 0, 1, 2]
输出:2
解释:数字 2 只出现一次,是独特的卡片。
样例3:
输入:
cards = [7, 3, 3, 7, 10]
输出:10
解释:10 是班级中唯一一个不重复的数字卡片。
约束条件
- 1 ≤ cards.length ≤ 1001
- 0 ≤ cards[i] ≤ 1000
- 班级人数为奇数
- 除了一个数字卡片只出现一次外,其余每个数字卡片都恰好出现两次。
思路
在 Python 中,集合是基于哈希表实现的,它提供了快速的查找、插入和删除操作。集合中的每个元素都是唯一的,这正是我们需要的特性,因为我们要找出出现奇数次的数字。
对于数组中的每个数字 num,代码检查该数字是否已经在 seen 集合中:
- 如果
num在seen中,说明这是第二次或更多次出现,因此我们从seen中移除它。这里利用了哈希表的快速查找特性。 - 如果
num不在seen中,说明这是第一次出现,我们将其添加到seen集合中。这里利用了哈希表的快速插入特性。 :由于集合是基于哈希表实现的,当发生哈希冲突时,Python 的集合会自动处理这些冲突,确保每个元素都是唯一的。
遍历完成后,seen 集合中剩下的元素就是出现奇数次的数字。由于集合中只能有一个元素(如果有多个出现奇数次的数字,那么至少有两个数字会相互抵消,最终只剩下一个),我们可以直接返回这个元素。
return list(seen)[0] 这一行代码将集合转换为列表,并返回列表中的第一个元素,即出现奇数次的数字。
最终实现代码只遍历了数组一次,并且利用了哈希表的快速查找和插入特性。时间复杂度为 O(n),其中 n 是数组 inp 的长度。空间复杂度为 O(k),其中 k 是数组中不同数字的数量。
def solution(inp):
seen = set()
for num in inp:
if num in seen:
seen.remove(num)
else:
seen.add(num)
# 此时seen集合中只有一个元素,就是那个独特的数字
return list(seen)[0]
第二题:连续字串和的整除问题
问题描述
小M是一个五年级的小学生,今天他学习了整除的知识,想通过一些练习来巩固自己的理解。他写下了一个长度为 n 的正整数序列 a_0, a_1, ..., a_{n-1},然后想知道有多少个连续子序列的和能够被一个给定的正整数 b 整除。你能帮小M解决这个问题吗?
测试样例
样例1:
输入:
n = 3,b = 3,sequence = [1, 2, 3]
输出:3
样例2:
输入:
n = 4,b = 5,sequence = [5, 10, 15, 20]
输出:10
样例3:
输入:
n = 5,b = 2,sequence = [1, 2, 3, 4, 5]
输出:6
思路
初始化计数器并嵌套循环,外循环for start in range(n): 这一行代码确定了子序列的起始位置。这里的 n 是序列 sequence 的长度。内循环for end in range(start, n): 这一行代码确定了子序列的结束位置。内层循环从 start 开始,确保子序列是非空的。
最终代码并没有直接使用哈希表,因为它的核心是遍历所有可能的子序列并计算它们的和。然而,哈希表可以用来优化某些类型的子序列问题,比如当我们需要快速查找特定和的子序列时。
然而在这个问题中,使用哈希表可能不会带来性能上的提升,因为我们需要检查所有可能的子序列,而不是查找特定的子序列。这里的关键是连续子序列的和,而不是子序列中的特定元素。
总的来说,具体问题具体考虑。
def solution(n, b, sequence):
count = 0 # 用于记录符合条件的子序列数量
# 外层循环,确定子序列的起始位置
for start in range(n):
current_sum = 0 # 当前子序列的和
# 内层循环,确定子序列的结束位置
for end in range(start, n):
current_sum += sequence[end] # 更新当前子序列的和
# 检查当前和是否能被 b 整除
if current_sum % b == 0:
count += 1 # 如果可以整除,则计数加一
return count