刷题记录:2.徒步旅行中的补给问题 | 豆包MarsCode AI刷题

120 阅读4分钟

问题描述

小R正在计划一次从地点A到地点B的徒步旅行,总路程需要 N 天。为了在旅途中保持充足的能量,小R每天必须消耗1份食物。幸运的是,小R在路途中每天都会经过一个补给站,可以购买食物进行补充。然而,每个补给站的食物每份的价格可能不同,并且小R最多只能同时携带 K 份食物。

现在,小R希望在保证每天都有食物的前提下,以最小的花费完成这次徒步旅行。你能帮助小R计算出最低的花费是多少吗?


测试样例

样例1:

输入:n = 5 ,k = 2 ,data = [1, 2, 3, 3, 2]
输出:9

样例2:

输入:n = 6 ,k = 3 ,data = [4, 1, 5, 2, 1, 3]
输出:9

样例3:

输入:n = 4 ,k = 1 ,data = [3, 2, 4, 1]
输出:10

MarsCode AI提示!

好的,让我们来分析一下这个问题,并提供一些思路提示。

问题理解

小R需要在 N 天内完成徒步旅行,每天需要消耗1份食物。每天经过的补给站食物价格可能不同,小R最多只能携带 K 份食物。目标是计算出完成旅行的最低花费。

数据结构选择

  1. 价格数组 data:记录每天的食物价格。
  2. stack:用于辅助计算下一个更低价格的天数。
  3. 数组 next_lower_price_day:记录从当前天数开始,下一个价格更低的天数。

算法步骤

  1. 预处理

    • 使用栈来计算 next_lower_price_day 数组,该数组记录从当前天数开始,下一个价格更低的天数。
    • 从后往前遍历价格数组,利用栈来维护一个递增的价格序列。
  2. 计算最低花费

    • 初始化当前食物数量 current_food 为0。
    • 遍历每一天,计算当天需要购买的食物数量。
    • 根据 next_lower_price_day 数组,确定在当前天数购买食物的最优数量。
    • 更新总花费 total_cost 和当前食物数量 current_food

关键点

  • 栈的使用:栈用于快速找到下一个更低价格的天数,从而决定在当前天数购买食物的最优数量。
  • 动态规划思想:通过预处理和遍历,逐步计算出最低花费。

代码提示

你可以参考以下步骤来实现代码:

  1. 预处理 next_lower_price_day 数组。
  2. 遍历每一天,计算当天需要购买的食物数量。
  3. 更新总花费和当前食物数量。

希望这些思路提示能帮助你更好地理解和解决这个问题。如果你有任何具体问题或需要进一步的帮助,请随时告诉我!

我的实现和思路

from collections import deque

def solution(n, k, data):
    """
    计算小R完成徒步旅行所需的最低花费。

    参数:
    n (int): 徒步旅行的总天数。
    k (int): 小R最多可以携带的食物份数。
    data (List[int]): 每个补给站的食物单价列表,长度为n。

    返回:
    int: 完成徒步旅行的最低总花费。
    """
    total_cost = 0
    dq = deque()  # 双端队列,用于维护滑动窗口中的最小食物价格

    for i in range(n):
        # 移除队列中价格大于等于当前补给站价格的所有元素
        while dq and data[dq[-1]] >= data[i]:
            dq.pop()
        
        # 将当前补给站的索引加入队列
        dq.append(i)
        
        # 移除队列中不在当前滑动窗口范围内的索引
        while dq and dq[0] < i - k + 1:
            dq.popleft()
        
        # 队列的第一个元素始终是当前滑动窗口内的最小价格
        total_cost += data[dq[0]]

    return total_cost

这道题的目的是求出每一天之后在接下来的 k 天内最低的食物价格,并且计算所有天数的最低价格之和。我的代码思路如下:

首先,我使用了一个 双端队列 deque 来维护一个滑动窗口。队列的作用是存储每天食物价格的索引,并确保队列中的元素是递增的(即,队列的最前端永远是当前窗口中的最小价格)。这样就能够在常数时间内获取到当前窗口中的最小价格。

在循环过程中,我首先将队列中的所有价格大于等于当前价格的元素移除,确保队列中的元素从头到尾是递增的。然后,我将当前价格的索引加入队列。接着,移除队列中不在当前滑动窗口范围内的索引,保证队列的范围不超过 k 天。

最后,我将队列最前面的元素(即当前窗口的最小价格)加入到 total_cost 中。

通过这种方法,我能够在遍历一遍数组的同时,快速地得到每一天之后 k 天内最低的价格。

总结来说,我的思路是通过双端队列来高效维护每个滑动窗口的最小值,避免了重复的计算,从而实现了较优的性能。