跳转至
纸质书已发行，详情请见这里

# 6.5 练习

## 6.5.1 知识巩固

### 1. 发生哈希冲突后怎样查找

一个哈希表有 5 个桶，哈希函数为 \(h(x)=x \bmod 5\)，冲突时把元素依次放进该桶的列表中。 依次插入 `[1, 6, 11, 7]`：

1. 写出 0～4 号桶中的内容；
2. 查找 6 时会先进入哪个桶，并依次检查哪些元素？
3. 根据第 1 问写出的桶内容，后插入的元素是否覆盖了先插入的元素？结合这种冲突处理方式说明理由。

参考答案

1. 因为 \(1\bmod5=6\bmod5=11\bmod5=1\)，而 \(7\bmod5=2\)，各桶为：

       0: []
       1: [1, 6, 11]
       2: [7]
       3: []
       4: []

2. 查找 6 时先进入 1 号桶，再依次比较 1、6，第二次比较时找到目标。

3. 哈希值相同只表示它们落入同一个桶，并不表示这些元素相等。链式地址把冲突元素都保存在桶内， 查询时再逐个比较，因此 1、6、11 不会互相覆盖。

### 2. 哈希表扩容后元素去哪儿

一个使用链式地址的哈希表原有 5 个桶，哈希函数为 \(h(x)=x\bmod5\)。 键 `[1, 6, 11]` 都在 1 号桶中。

现在把哈希表扩容为 7 个桶，哈希函数相应变为 \(h(x)=x\bmod7\)：

1. 分别计算 1、6、11 的新桶号。
2. 扩容后哪些桶中有元素？
3. 扩容时能否把原来 1 号桶中的列表原样复制到新的 1 号桶？结合第 1、2 问的结果说明理由。

参考答案

1. 新桶号分别为：

   - \(1\bmod7=1\)；
   - \(6\bmod7=6\)；
   - \(11\bmod7=4\)。

2. 1 号桶保存 1，4 号桶保存 11，6 号桶保存 6。三个键不再挤在同一个桶中。

3. 不能原样复制。桶号由“键对桶数取余”得到。桶数从 5 变成 7 后，同一个键的新桶号可能改变， 因此必须重新计算每个键的位置。若把旧的 1 号桶原样复制过去，之后按新公式查找 6 和 11 时， 会分别前往 6 号桶和 4 号桶，从而找不到它们。

### 3. 删除 6 后还能找到 11 吗

一个哈希表有 5 个位置，索引为 `0～4`，哈希函数为 \(h(x)=x\bmod5\)。 发生冲突时，从哈希函数算出的索引开始，向右寻找第一个空位。

依次插入 `[1, 6, 11]`：

1. 三个数最终分别放在哪个索引？
2. 查找 11 时，会依次检查哪些索引？
3. 如果删除 6 时直接把它的位置改成“从未使用的空位”，而查找遇到空位就停止， 再查找 11 时会发生什么？这个查找结果是否正确？如果有问题，应怎样避免？

参考答案

1. 1 放在索引 1。6 也映射到索引 1，发生冲突后放在索引 2。 11 同样从索引 1 开始，依次跳过已占用的索引 1、2，最终放在索引 3。

2. 查找 11 时依次检查索引 `1、2、3`，在索引 3 找到它。

3. 如果把索引 2 改成表示“从未使用”的空位，查找 11 时检查索引 1 后就会在索引 2 停止， 从而错误地认为 11 不存在。删除时应留下“已删除”标记： 查找遇到该标记时继续检查下一个索引（越过索引 4 后回到索引 0），而以后的插入仍可重新使用这个位置。

## 6.5.2 编程练习

### 1. 比较两个字符串的字符组成

给定两个只含小写英文字母的字符串 `s` 和 `t`。 可以任意调整 `s` 中字符的位置，但不能添加、删除或替换字符。

请判断调整后能否得到 `t`；可以则返回 `true`，否则返回 `false`。 请使用哈希表记录各字母的出现次数，不对字符串中的字符排序。

解题提示

1. 两个字符串长度不同，它们的字符组成一定不同
2. 用哈希表记录每种字母的数量；扫描 s 时把对应计数加 1
3. 扫描 t 时把对应计数减 1；所有计数最终都为 0，字符组成才相同

LeetCode 题目解析

##### 欢迎在评论区留下你的见解、问题或建议