返回首页返回书籍《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纸质书
第 113 / 119 节

第 113 节 · SECTION 113

练习

知识巩固

每次选最大硬币一定最好吗

硬币面值为 [1, 7, 10],目标金额为 14。

  1. 按“每次取不超过剩余金额的最大面值”执行,写出所取硬币;
  2. 是否存在使用更少硬币的方案?如果存在,请写出一种;如果不存在,请说明理由;
  3. 这能否说明该贪心策略对任意硬币面值都正确?

参考答案

  1. 贪心依次选择 10 + 1 + 1 + 1 + 1,共 5 枚硬币。

  2. 存在使用更少硬币的方案:7 + 7,只需 2 枚硬币。

  3. 不能。这个反例说明,对任意硬币面值,每次选择当前能取的最大面值并不一定得到最少硬币数; 眼前最大的选择可能破坏后续更好的组合。

背包应该先装哪件物品

一个容量为 4 千克的背包中可以装入以下物品,物品允许只取一部分, 所取价值与重量成正比:

  • 物品 A:重量 4 千克,价值 20;
  • 物品 B:重量 3 千克,价值 18。
  1. 两件物品每千克的价值分别是多少?应先装哪一件?
  2. 按分数背包的贪心策略装满背包,最终价值是多少?
  3. 在物品可以切分、背包限制总重量的情况下,选择物品时应该比较总价值还是每千克价值?为什么?

参考答案

  1. A 每千克价值为 20 ÷ 4 = 5,B 每千克价值为 18 ÷ 3 = 6, 因此应先装单位价值更高的 B。

  2. 先装入全部 B,占用 3 千克、获得价值 18;剩余 1 千克容量, 再装入 1 千克 A,获得价值 5。最终价值为 18 + 5 = 23。

  3. 背包限制的是总重量,而且物品可以切分,所以应比较单位重量的价值。 A 的总价值虽然更高,但每千克价值低于 B;若先装满 A,只能得到价值 20。

两个指针下一步怎样移动

隔板高度为 [1, 8, 6, 2, 5],用首尾双指针寻找最大容量。 容量等于“两块隔板中较短者的高度 × 两块隔板的下标距离”。

  1. 初始时左指针在下标 0、右指针在下标 4,当前容量是多少?下一步应移动哪个指针?
  2. 按照第 1 问的选择移动一次后,两个指针分别位于哪个下标?此时容量是多少?下一步又应移动哪个指针?
  3. 在当前一对隔板中,可以移动较短隔板对应的指针,也可以移动较长隔板对应的指针。哪一种移动仍有可能得到更大的容量?为什么?

参考答案

  1. 当前容量为 min(1, 5) × (4 - 0) = 4。左侧隔板较短,因此移动左指针。

  2. 移动左指针后,两个指针分别位于下标 1 和 4。当前容量为 min(8, 5) × (4 - 1) = 15。右侧隔板较短,因此下一步移动右指针。

  3. 移动较短隔板对应的指针,才仍有可能得到更大的容量。移动较长隔板后,两块隔板的距离一定缩短,而容器高度仍受未移动的短板限制, 只可能不变或变小。因此容量不可能超过移动前;只有移动短板,才有机会遇到更高的隔板。

编程练习

分数背包

给定等长数组 wgt 和 val,其中 wgt[i] > 0、val[i] >= 0,背包容量 cap >= 0。 每种物品只有一件,但允许只装入其中一部分, 获得的价值按所装重量占该物品总重量的比例计算。请使用贪心算法, 并以实数返回背包能够获得的最大总价值。

解题提示

  1. 先计算每件物品的单位重量价值 val[i] / wgt[i],除法结果要保留小数
  2. 单位价值越高的物品越先装入背包
  3. 若剩余容量小于当前物品重量,就装入恰好填满背包的部分并结束