问题
题目列表第56道:贪心猫的鱼干大分配,难度为中
问题描述
在猫星球上,小R负责给一行排队的猫分发鱼干。每只猫有一个等级,等级越高的猫应该得到更多的鱼干。规则如下:
- 每只猫至少得到一斤鱼干。
- 如果一只猫的等级高于它相邻的猫,它就应该得到比相邻的猫更多的鱼干。
小R想知道,为了公平地满足所有猫的等级差异,他至少需要准备多少斤鱼干。
测试样例
样例1:
输入:
n = 3, cats_levels = [1, 2, 2]
输出:4
样例2:
输入:
n = 6, cats_levels = [6, 5, 4, 3, 2, 16]
输出:17
样例3:
输入:
n = 20, cats_levels = [1, 2, 2, 3, 3, 20, 1, 2, 3, 3, 2, 1, 5, 6, 6, 5, 5, 7, 7, 4]
输出:35
解题思路
这道题看似并不难,但是也容易出现没思路的情况。对猫的等级数组做一次正向遍历显然是不够的,因为这只能保证相邻且在右边等级更高的猫得到的鱼干更多,而不总能保证相邻且在右边等级更低的猫得到的鱼干更少(举个特例,给第一只猫分一斤鱼干,而它右边的猫等级越来越小,但一斤已经是最少了,那么就满足不了题目的要求)。为了确保每只猫得到的鱼干数量满足它们的等级差异,我们可以使用贪心算法来解决这个问题。可以两次遍历猫的等级数组,一次从左到右,确保每只猫比它左边的猫得到更多的鱼干(如果它的等级更高);另一次从右到左,确保每只猫比它右边的猫得到更多的鱼干(如果它的等级更高)。最终,每只猫应该得到的是这两个过程中计算出的最大值。为什么是取最大值,而不是取最小或者别的计算呢?因为取最大一定能既满足正向遍历的要求(如果当前猫等级高于左边的猫那么得到的鱼干更多),又满足逆向遍历的要求(如果当前猫等级高于右边的猫那么得到的鱼干更多),且能得到满足题目要求的最少鱼干总数。两趟遍历后,只要将答案数组求和即可。从这道题里我们也能体会贪心算法的思想,在遍历等级数组时我们总是求出满足题目要求的局部最优解,而整体的最优解就由这些满足条件的局部最优解构成。
具体实现
fish_dry = [1] * n
# 第一次遍历,从前向后,保证当前猫的鱼干数量不低于左侧猫的鱼干数量
for i in range(1, n):
if cats_levels[i] > cats_levels[i - 1]:
fish_dry[i] = max(fish_dry[i], fish_dry[i - 1] + 1)
# 第二次遍历,从后向前,保证当前猫的鱼干数量不低于右侧猫的鱼干数量
for i in range(n - 2, -1, -1):
if cats_levels[i] > cats_levels[i + 1]:
fish_dry[i] = max(fish_dry[i], fish_dry[i + 1] + 1)
# 计算总的鱼干数量
total_fish_dry = sum(fish_dry)
return total_fish_dry
结语
通过这道题,我们对贪心算法的原理,使用条件和写法有了更加深刻的认识,希望以后能挑战更多更难的题目,在实践中体会算法思想的精髓。