返回首页返回书籍《Hello 算法》
目录

目录 · CONTENTS

  1. 01序
  2. 02前言
  3. 03关于本书
  4. 04如何使用本书
  5. 05小结
  6. 06初识算法
  7. 07算法无处不在
  8. 08算法是什么
  9. 09小结
  10. 10复杂度分析
  11. 11算法效率评估
  12. 12迭代与递归
  13. 13时间复杂度
  14. 14空间复杂度
  15. 15小结
  16. 16练习
  17. 17数据结构
  18. 18数据结构分类
  19. 19基本数据类型
  20. 20数字编码
  21. 21字符编码
  22. 22小结
  23. 23练习
  24. 24数组与链表
  25. 25数组
  26. 26链表
  27. 27列表
  28. 28内存与缓存
  29. 29小结
  30. 30练习
  31. 31栈与队列
  32. 32栈
  33. 33队列
  34. 34双向队列
  35. 35小结
  36. 36练习
  37. 37哈希表
  38. 38哈希表
  39. 39哈希冲突
  40. 40哈希算法
  41. 41小结
  42. 42练习
  43. 43树
  44. 44二叉树
  45. 45二叉树遍历
  46. 46二叉树数组表示
  47. 47二叉搜索树
  48. 48AVL 树
  49. 49小结
  50. 50练习
  51. 51堆
  52. 52堆
  53. 53建堆操作
  54. 54Top-k 问题
  55. 55小结
  56. 56练习
  57. 57图
  58. 58图
  59. 59图的基础操作
  60. 60图的遍历
  61. 61小结
  62. 62练习
  63. 63搜索
  64. 64二分查找
  65. 65二分查找插入点
  66. 66二分查找边界
  67. 67哈希优化策略
  68. 68重识搜索算法
  69. 69小结
  70. 70练习
  71. 71排序
  72. 72排序算法
  73. 73选择排序
  74. 74冒泡排序
  75. 75插入排序
  76. 76快速排序
  77. 77归并排序
  78. 78堆排序
  79. 79桶排序
  80. 80计数排序
  81. 81基数排序
  82. 82小结
  83. 83练习
  84. 84分治
  85. 85分治算法
  86. 86分治搜索策略
  87. 87构建二叉树问题
  88. 88汉诺塔问题
  89. 89小结
  90. 90练习
  91. 91回溯
  92. 92回溯算法
  93. 93全排列问题
  94. 94子集和问题
  95. 95n 皇后问题
  96. 96小结
  97. 97练习
  98. 98动态规划
  99. 99初探动态规划
  100. 100动态规划问题特性
  101. 101动态规划解题思路
  102. 1020-1 背包问题
  103. 103完全背包问题
  104. 104编辑距离问题
  105. 105小结
  106. 106练习
  107. 107贪心
  108. 108贪心算法
  109. 109分数背包问题
  110. 110最大容量问题
  111. 111最大切分乘积问题
  112. 112小结
  113. 113练习
  114. 114附录
  115. 115编程环境安装
  116. 116一起参与创作
  117. 117术语表
  118. 118参考文献
  119. 119纸质书
第 42 / 119 节

第 42 节 · SECTION 42

练习

知识巩固

发生哈希冲突后怎样查找

一个哈希表有 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 不会互相覆盖。

哈希表扩容后元素去哪儿

一个使用链式地址的哈希表原有 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 号桶,从而找不到它们。

删除 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),而以后的插入仍可重新使用这个位置。

编程练习

比较两个字符串的字符组成

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

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

解题提示

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

LeetCode 题目解析