leetcode2944.购买水果需要的最少金币数

leetcode2944.购买水果需要的最少金币数
univerexplorer2944. 购买水果需要的最少金币数
中等(动态规划)
给你一个 下标从 1 开始的 整数数组 prices ,其中 prices[i] 表示你购买第 i 个水果需要花费的金币数目。
水果超市有如下促销活动:
- 如果你花费
prices[i]购买了下标为i的水果,那么你可以免费获得下标范围在[i + 1, i + i]的水果。
注意 ,即使你 可以 免费获得水果 j ,你仍然可以花费 prices[j] 个金币去购买它以获得它的奖励。
请你返回获得所有水果所需要的 最少 金币数。
示例 1:
输入: prices = [3,1,2]
输出: 4
解释:
- 用
prices[0] = 3个金币购买第 1 个水果,你可以免费获得第 2 个水果。- 用
prices[1] = 1个金币购买第 2 个水果,你可以免费获得第 3 个水果。- 免费获得第 3 个水果。
请注意,即使您可以免费获得第 2 个水果作为购买第 1 个水果的奖励,但您购买它是为了获得其奖励,这是更优化的。
示例 2:
输入: prices = [1,10,1,1]
输出: 2
解释:
- 用
prices[0] = 1个金币购买第 1 个水果,你可以免费获得第 2 个水果。- 免费获得第 2 个水果。
- 用
prices[2] = 1个金币购买第 3 个水果,你可以免费获得第 4 个水果。- 免费获得第 4 个水果。
示例 3:
输入: prices = [26,18,6,12,49,7,45,45]
输出: 39
解释:
- 用
prices[0] = 26个金币购买第 1 个水果,你可以免费获得第 2 个水果。- 免费获得第 2 个水果。
- 用
prices[2] = 6个金币购买第 3 个水果,你可以免费获得第 4,5,6(接下来的三个)水果。- 免费获得第 4 个水果。
- 免费获得第 5 个水果。
- 用
prices[5] = 7个金币购买第 6 个水果,你可以免费获得第 7 和 第 8 个水果。- 免费获得第 7 个水果。
- 免费获得第 8 个水果。
请注意,即使您可以免费获得第 6 个水果作为购买第 3 个水果的奖励,但您购买它是为了获得其奖励,这是更优化的。
代码一:递归
1 | class Solution: |
思路:
下标为1的水果是必须要购买的,因此从1开始。购买第 pos 个水果,那么区间 [pos + 1, 2 * pos] 中的水果是可以免费获得的。如果 pos*2+1 超过数组长度,那么就返回购买的第 pos 个水果的金币数;否则依次考虑区间中的水果是否购买,返回最小的花费。
复杂度分析
- 时间复杂度:O(n^2)。
- 空间复杂度:O(n)。
代码二:动态规划
1 | class Solution: |
思路:
我们可以去掉递归中的「递」,只保留「归」的部分,即自底向上计算。
具体来说,f[i] 的定义和 func1(pos) 的定义是一样的,都表示在购买第 i 个水果的前提下,获得第 i 个及其后面的水果所需要的最少金币数。注意 i 从 1 开始。
相应的递推式(状态转移方程)也和 func1 一样:
$$
f[i]=prices[i]+ \underset{j=i+1}{\overset{2i+1}{min}}
f[j]
$$
注:由于从比
i更大的j转移过来,所以必须倒着计算f。
初始值:当
$$
i \ge \left \lfloor \frac{n+1}{2} \right \rfloor
$$
时,f[i] = prices[i]。
答案:f[1]。
注:由于传入的 prices 数组的下标是从 0 开始的,代码实现时下标要减一。
复杂度分析
- 时间复杂度:O(n^2),其中 n 为 prices 的长度。
- 空间复杂度:O(1)。Python 忽略切片开销。











