学习心得:贪心猫的鱼干大分配
在猫星球上,小R负责给一行排队的猫分发鱼干。每只猫有一个等级,等级越高的猫应该得到更多的鱼干。猫与猫之间的关系可以通过一个等级数组 cats_levels 来表示。我们的目标是根据猫的等级分配鱼干,遵循以下规则:
- 每只猫至少得到一斤鱼干。
- 如果一只猫的等级比相邻的猫高,那么它应该得到比相邻的猫更多的鱼干。
- 如果两只猫的等级相同,它们得到的鱼干可以相同。
我们的任务是计算为了公平地满足所有猫的等级差异,至少需要多少斤鱼干。
解决方案:贪心算法
这个问题的核心是如何公平地分配鱼干,使得满足规则的同时,鱼干总数最少。这个问题可以通过贪心算法来解决。
思路
- 初始化鱼干数组:首先,为每只猫分配 1 斤鱼干,确保每只猫至少有一斤鱼干。
- 左到右遍历:从左到右遍历猫的等级数组。如果当前猫的等级比前一只猫高,则说明当前猫应该得到比前一只猫多的鱼干。因此我们更新当前猫的鱼干数量。
- 右到左遍历:从右到左遍历猫的等级数组。如果当前猫的等级比后一只猫高,并且当前猫的鱼干数量不满足比后一只猫多的条件,那么我们需要调整当前猫的鱼干数量。
通过两次遍历,确保每只猫的鱼干数量都满足题目的要求,并且总数最小。
代码实现
def solution(n, cats_levels):
# 初始化每只猫的鱼干数量,初始时每只猫得到 1 斤鱼干
fish = [1] * n
# 第一次遍历:从左到右调整鱼干数量
for i in range(1, n):
if cats_levels[i] > cats_levels[i - 1]:
fish[i] = fish[i - 1] + 1
# 第二次遍历:从右到左调整鱼干数量
for i in range(n - 2, -1, -1):
if cats_levels[i] > cats_levels[i + 1]:
fish[i] = max(fish[i], fish[i + 1] + 1)
# 返回鱼干的总和
return sum(fish)
# 测试用例
cats_levels1 = [1, 2, 2]
cats_levels2 = [6, 5, 4, 3, 2, 16]
cats_levels3 = [1, 2, 2, 3, 3, 20, 1, 2, 3, 3, 2, 1, 5, 6, 6, 5, 5, 7, 7, 4]
print(solution(3, cats_levels1)) # 输出:4
print(solution(6, cats_levels2)) # 输出:17
print(solution(20, cats_levels3)) # 输出:35
复杂度分析
- 时间复杂度:( O(n) ),其中 (n) 是猫的数量。我们分别从左到右和从右到左遍历一次猫的等级数组。
- 空间复杂度:( O(n) ),需要一个长度为 (n) 的数组来存储每只猫的鱼干数量。
贪心算法的优势
贪心算法的基本思想是通过局部最优解来逐步逼近全局最优解。在本题中,我们通过两次遍历数组,在每次更新时都选择当前最合适的分配方式,保证了每只猫的鱼干数量符合条件。贪心算法非常适合这种局部最优选择能够推导出全局最优解的问题,因此效率较高。
学习心得
-
贪心算法的应用: 贪心算法是一种常见的算法设计思想,它的基本思想是通过局部最优选择来达到全局最优。虽然贪心算法通常能给出较高效的解法,但它并不适用于所有问题,因为某些问题需要考虑全局的优化,而不仅仅是局部的最优选择。像本题中,猫的鱼干分配符合贪心算法的条件,因为每次局部的鱼干调整是最优的。
-
题目中的贪心选择: 在本题中,贪心算法的选择非常明确:当当前猫的等级大于相邻猫时,我们立即为它分配更多的鱼干。通过从左到右和从右到左两次遍历,保证了每只猫的鱼干分配都能符合规则。通过两次遍历来“修正”鱼干数,这实际上是一个“局部最优”的选择方式,因为我们逐步解决了每个局部的冲突问题,最终得到的解是全局最优的。
-
边界条件的考虑: 在实现过程中,我们需要确保猫的等级比较操作是基于相邻猫的,而不是绝对值的比较。因此,当遍历时,需要考虑到相邻猫的关系。边界条件比如最左边和最右边的猫,可能会在第一次遍历时没有影响,需要通过第二次遍历来修正。
-
算法的稳定性: 通过两次遍历,算法确保了相邻猫的鱼干数量能够符合规则,同时它的时间复杂度为 ( O(n) ),非常适合处理大规模数据。其稳定性体现在贪心算法通过逐步修正的方式有效保证了最终解的最优性。
知识总结
-
贪心算法的步骤:
- 定义一个贪心选择准则。
- 每次选择局部最优解。
- 通过局部最优解逐步构造全局最优解。
-
贪心算法的应用场景: 贪心算法适用于那些能够通过局部最优选择推导出全局最优解的问题。常见的贪心算法问题包括:最短路径问题(Dijkstra 算法),活动选择问题,背包问题(某些特殊情况),区间调度问题等。
-
与动态规划的对比: 动态规划通常适用于问题的解可以通过子问题的解来构造的情况,并且子问题之间有重叠。而贪心算法更依赖于问题的“贪心选择性质”,即每一步的局部最优解能够推导出全局最优解。因此,贪心算法适用于那些没有子问题重叠且每一步选择是局部最优的情况。
学习计划
在深入理解并掌握贪心算法后,我计划继续进行以下几项学习:
- 解决更多贪心问题:如活动选择问题、最小生成树问题(Kruskal 算法、Prim 算法)、哈夫曼编码等。
- 结合动态规划:在很多实际问题中,贪心算法和动态规划是互补的,需要理解如何根据问题的特性选择合适的算法。
- 提升编程技能:通过编写更多的算法和解题代码,提升算法应用的熟练度和解决问题的效率。
使用豆包AI刷题功能
豆包AI的刷题功能可以帮助我快速解决各种算法题目,包括贪心算法、动态规划、回溯法等。通过这种刷题方式,我可以获得即时反馈,了解自己在解题过程中存在的不足,并及时调整学习策略。豆包AI还能够提供详细的题解分析,帮助我更好地理解每个问题的解决思路和技巧。