问题描述
小R正在计划一次从地点A到地点B的徒步旅行,总路程需要 N 天。为了在旅途中保持充足的能量,小R每天必须消耗1份食物。幸运的是,小R在路途中每天都会经过一个补给站,可以购买食物进行补充。然而,每个补给站的食物每份的价格可能不同,并且小R最多只能同时携带 K 份食物。
现在,小R希望在保证每天都有食物的前提下,以最小的花费完成这次徒步旅行。你能帮助小R计算出最低的花费是多少吗?
题解
public static int solution(int n, int k, int[] data) {
// Edit your code here
int length = data.length;
int[] dp = new int[length];
dp[0] = data[0];
for (int i = 1; i < length; i++) {
dp[i] = dp[i - 1] + data[i];
for (int j = i - 1; j >= i - k + 1 && j >= 0; j--) {
dp[i] = Math.min(dp[i], dp[i - 1] + data[j]);
}
}
return dp[length - 1];
}
思路解析
问题的目标是解决小R在途经补给站时,如何以最小花费完成旅程的问题。这里的关键在于动态规划方法的应用。代码中的核心思想是:
-
动态规划状态定义:
dp[i]表示从第 0 天开始到第i天,小R所需要的最小花费。
-
状态转移方程:
- 初始状态:
dp[0] = data[0],即第 0 天的食物价格为唯一花费。 - 递推关系:
dp[i] = min(dp[i], dp[i - 1] + data[j]),在从前面 K 天中选择某一天补给,尝试以最优价格更新当天的总花费。
- 初始状态:
-
限制条件:
- 小R每天需要 1 份食物,因此每天都需要至少购买 1 份。
- 小R最多可以携带 K 份食物,因此每次补给最多只能覆盖接下来的 K 天需求。
代码通过一个双层循环来实现:
- 外层循环遍历每天的状态。
- 内层循环从第
i-1天开始向前最多回溯到i-K+1天,用来计算从某一天补给到第i天的最小花费。
解题步骤
-
初始化:
- 创建一个数组
dp,用于存储每天的最小花费。 - 设置第一天的花费为
dp[0] = data[0]。
- 创建一个数组
-
遍历每一天:
-
对于第
i天:- 初始将其花费设置为前一天的花费加当天的补给站价格:
dp[i] = dp[i-1] + data[i]。 - 使用内层循环检查从第
i-1天往前最多K天的补给方案,计算出更优的总花费。 - 更新
dp[i]。
- 初始将其花费设置为前一天的花费加当天的补给站价格:
-
-
返回结果:
- 返回
dp[length - 1],即到达最后一天的最小花费。
- 返回
时间复杂度
时间复杂度为 O(N * K)。