中等题:贪心猫的鱼干大分配

120 阅读4分钟

贪心猫的鱼干大分配:问题解析与代码详解

问题描述

在猫星球上,小R负责给排队的猫分发鱼干。每只猫有一个等级,等级越高的猫应该得到更多的鱼干。具体规则如下:

  1. 每只猫至少得到一斤鱼干。
  2. 如果一只猫的等级高于它相邻的猫,它就应该得到比相邻的猫更多的鱼干。

我们的目标是计算小R至少需要准备多少斤鱼干,以公平地满足所有猫的等级差异。

思路解析

这个问题可以通过贪心算法来解决。我们需要确保在分配鱼干时,满足以下两个条件:

  1. 每只猫至少获得 1 斤鱼干。
  2. 对于每只猫,如果它的等级高于相邻的猫,则它的鱼干数量必须比相邻猫的鱼干数量多。

步骤

  1. 初始化鱼干数量:创建一个与猫的数量相同的数组 candies,并将每个元素初始化为 1,表示每只猫至少获得 1 斤鱼干。

  2. 从左到右遍历:遍历猫的等级列表,如果当前猫的等级高于前一只猫,则将当前猫的鱼干数量设置为前一只猫的鱼干数量加 1。

  3. 从右到左遍历:再从右向左遍历猫的等级列表,如果当前猫的等级高于后一只猫,则将当前猫的鱼干数量设置为当前值和后一只猫的鱼干数量加 1 的最大值。

  4. 计算总鱼干数量:最后,将 candies 数组中的所有元素相加,得到总的鱼干数量。

图解

假设我们有 5 只猫,等级为 [1, 3, 2, 4, 3]。我们可以用以下步骤进行分配:

  • 初始化 candies 数组为 [1, 1, 1, 1, 1]
  • 从左到右遍历:
    • 对于猫 2(等级 3),比猫 1(等级 1)高,candies 更新为 [1, 2, 1, 1, 1]
    • 对于猫 3(等级 2),不高于猫 2,保持不变。
    • 对于猫 4(等级 4),比猫 3(等级 2)高,candies 更新为 [1, 2, 1, 2, 1]
    • 对于猫 5(等级 3),不高于猫 4,保持不变。
  • 从右到左遍历:
    • 对于猫 4(等级 4),比猫 5(等级 3)高,candies 更新为 [1, 2, 1, 2, 2]
    • 对于猫 3(等级 2),不高于猫 4,保持不变。
    • 对于猫 2(等级 3),比猫 1(等级 1)高,保持不变。

最终,candies 数组为 [1, 2, 1, 2, 2],总鱼干数量为 8。

代码详解

以下是实现上述逻辑的代码:

def solution(n, cats_levels):
    # 初始化每只猫的鱼干数量
    candies = [1] * n
    
    # 从左到右遍历
    for i in range(1, n):
        if cats_levels[i] > cats_levels[i - 1]:
            candies[i] = candies[i - 1] + 1
    
    # 从右到左遍历
    for i in range(n - 2, -1, -1):
        if cats_levels[i] > cats_levels[i + 1]:
            candies[i] = max(candies[i], candies[i + 1] + 1)
    
    # 计算总鱼干数量
    return sum(candies)

if __name__ == "__main__":
    # 测试样例
    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)  # 输出: True
    print(solution(6, cats_levels2) == 17)  # 输出: True
    print(solution(20, cats_levels3) == 35)  # 输出: True

代码分析

  1. 初始化candies = [1] * n 确保每只猫至少获得 1 斤鱼干。
  2. 左到右遍历:通过 for i in range(1, n) 遍历每只猫,检查相邻猫咪的等级并更新鱼干数量。
  3. 右到左遍历:通过 for i in range(n - 2, -1, -1) 进行反向遍历,确保反向条件也得到满足。
  4. 总和计算return sum(candies) 返回所有猫咪鱼干的总和。

复杂度分析

  • 时间复杂度:O(n),因为我们只遍历了数组两次。
  • 空间复杂度:O(n),我们使用了一个额外的数组 candies 来存储每只猫的鱼干数量。

总结

通过贪心算法,我们能够高效地解决猫咪鱼干分配的问题。通过两次遍历,我们能够确保每只猫都获得了合适的鱼干,满足了等级的要求。这种方法不仅简单直观,而且在实际应用中也非常高效。 在解决“贪心猫的鱼干大分配”问题的过程中,我深刻体会到贪心算法的有效性。通过两次遍历(左到右和右到左),我们确保了每只猫在满足相邻猫鱼干分配规则的情况下,尽量减少总鱼干数量。这种分步思考的方式让我清晰理解了每一步的影响。

在编写代码时,我注重可读性和维护性,合理命名变量并添加注释,确保代码易于理解。同时,我重视边界条件的处理,避免潜在的错误。在完成后,我进行了复杂度分析,确认算法在大规模数据下的表现。

通过这个问题,我意识到理论知识与实践能力同样重要,今后我将继续通过解决各种算法题目来巩固自己的能力,提升编程水平。这个过程让我更加自信地面对未来更复杂的挑战。