问题描述
在猫星球上,小R负责给一行排队的猫分发鱼干。每只猫有一个等级,等级越高的猫应该得到更多的鱼干。规则如下:
- 每只猫至少得到一斤鱼干。
- 如果一只猫的等级高于它相邻的猫,它就应该得到比相邻的猫更多的鱼干。
小R想知道,为了公平地满足所有猫的等级差异,他至少需要准备多少斤鱼干。
思路解析
1. 理解问题背景与规则
已知有一排猫,每只猫都有对应的等级,我们的任务是给这些猫分发鱼干,并且要遵循一定的规则来保证分配的公平性(基于猫的等级差异)。
分配规则: 每只猫至少能得到 1 斤鱼干。 如果一只猫的等级高于它相邻的猫,它就应该得到比相邻猫更多的鱼干。
2. 确定解题方向
为了找到满足规则的最少鱼干总斤数,需要考虑每只猫与相邻猫的等级关系,然后基于这些关系逐步确定每只猫应分配的鱼干数量,最后将所有猫的鱼干数量相加即可得到总斤数。整体解题过程可以通过分阶段处理来实现,依次从不同方向去分析猫之间的等级影响。
3. 从左到右分析猫的等级关系(第一轮)
从队伍的左边开始,依次比较每只猫和它右边相邻猫的等级情况。 对于每只猫(除了最左边第一只猫,因为它左边没有相邻猫可比较了,默认先分配 1 斤鱼干):
1.比较当前猫的等级与它右边相邻猫的等级。
(1)如果当前猫的等级大于右边相邻猫的等级,按照规则,当前猫应该比右边相邻猫多获得 1 斤鱼干,所以当前猫分配的鱼干数量就是右边相邻猫已分配(或初始设定为 1 斤)的鱼干数量加 1。 (2)如果当前猫的等级小于等于右边相邻猫的等级,当前猫暂时就按至少 1 斤鱼干分配(后续可能会根据其他比较情况再调整)。
通过这样从左到右的一轮比较,我们能初步确定每只猫基于其左边相邻猫情况应分配的鱼干数量,得到一个从左到右角度的鱼干分配参考值。
4. 从右到左分析猫的等级关系(第二轮)
接着从队伍的右边开始,逆向依次比较每只猫和它左边相邻猫的等级情况。 对于每只猫(除了最右边最后一只猫,它右边没有相邻猫可比较了,其鱼干数量可能已经在第一轮或者初始设定好了):
- 比较当前猫的等级与它左边相邻猫的等级。
(1) 如果当前猫的等级大于左边相邻猫的等级,此时要保证当前猫比左边相邻猫得到更多鱼干,所以需要重新审视当前猫的鱼干数量,取当前猫已有的鱼干数量(可能是第一轮确定的,也可能是初始的 1 斤)和左边相邻猫鱼干数量加 1 这两者中的较大值,作为当前猫最终应分配的鱼干数量。这样做既能满足当前猫等级更高需更多鱼干的规则,又能综合考虑之前从左到右分析时确定的情况。
(2) 如果当前猫的等级小于等于左边相邻猫的等级,当前猫的鱼干数量保持之前确定的值(因为已经满足规则要求了)。
经过这一轮从右到左的比较,进一步调整并最终确定每只猫基于其两边相邻猫情况都能满足规则的鱼干分配数量。
5. 计算最少鱼干总斤数
在完成了上述两轮从不同方向对猫等级关系的分析和鱼干数量调整后,此时每只猫都有了最终确定的鱼干分配数量。将所有猫最终分配的鱼干数量进行累加求和,得到的总和就是为了满足所有猫等级差异,按照规则公平分配时最少需要准备的鱼干总斤数。
综上所述,通过先从左到右、再从右到左分析猫之间的等级关系,逐步确定每只猫的鱼干分配数量,最后求和得到最少鱼干总斤数,以此解决了根据猫等级来公平分发鱼干的问题。****
代码展示
def solution(n, cats_levels):
left = [1] * n
right = [1] * n
res = 0
for i in range(1, n):
if cats_levels[i] > cats_levels[i - 1]:
left[i] = left[i - 1] + 1
for i in range(n - 2, -1, -1):
if cats_levels[i] > cats_levels[i + 1]:
right[i] = right[i + 1] + 1
for i in range(n):
res += max(left[i], right[i])
return res
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)
print(solution(6, cats_levels2) == 17)
print(solution(20, cats_levels3) == 35)
优化思路
思路一:减少列表初始化开销
在原代码中,分别初始化了 left 和 right 两个长度为 n 的列表,每个元素初始值都为 1。其实可以利用 Python 的生成器表达式来更高效地初始化这两个列表,避免不必要的内存占用和初始化赋值操作开销。
思路二:合并最后累加的循环
原代码中先分别从左到右、从右到左遍历更新 left 和 right 列表,然后又单独使用一个循环来累加每只猫最终的鱼干数量。可以考虑在从右到左遍历更新 right 列表的过程中,直接完成每只猫最终鱼干数量的确定和累加操作,这样就可以省去最后那个单独的累加循环,减少一次对列表的完整遍历,提升效率。
优化代码
def solution(n, cats_levels):
left = [1] * n
# 使用生成器表达式初始化right列表,更高效
right = (1 for _ in range(n))
res = 0
for i in range(1, n):
if cats_levels[i] > cats_levels[i - 1]:
left[i] = left[i - 1] + 1
# 从右到左遍历,合并确定每只猫最终鱼干数并累加的操作
for i in range(n - 1, -1, -1):
if i < n - 1 and cats_levels[i] > cats_levels[i + 1]:
right_value = right.__next__() + 1
else:
right_value = right.__next__()
# 取left和right_value的较大值确定当前猫最终鱼干数并累加
res += max(left[i], right_value)
return res