力扣118场双周赛第三题-购买水果需要的最少金币数

文章讲述了如何使用动态规划解决一个关于水果购买的问题,给出了一种从后往前遍历的解题步骤,确定在满足特定促销活动下获取所有水果所需的最少金币数。
摘要由CSDN通过智能技术生成

问题描述

你在一个水果超市里,货架上摆满了玲琅满目的奇珍异果。

给你一个下标从 1 开始的数组 prices ,其中 prices[i] 表示你购买第 i 个水果需要花费的金币数目。

水果超市有如下促销活动:

  • 如果你花费 price[i] 购买了水果 i ,那么接下来的 i 个水果你都可以免费获得。

注意 ,即使你 可以 免费获得水果 j ,你仍然可以花费 prices[j] 个金币去购买它以便能免费获得接下来的 j 个水果。

请你返回获得所有水果所需要的 最少 金币数。

示例

输入:prices = [3,1,2]
输出:4
解释你可以按如下方法获得所有水果:
- 花 3 个金币购买水果 1 ,然后免费获得水果 2 。
- 花 1 个金币购买水果 2 ,然后免费获得水果 3 。
- 免费获得水果 3 。
注意,虽然你可以免费获得水果 2 ,但你还是花 1 个金币去购买它,因为这样的总花费最少。
购买所有水果需要最少花费 4 个金币。
输入:prices = [1,10,1,1]
输出:2
解释:你可以按如下方法获得所有水果:
- 花 1 个金币购买水果 1 ,然后免费获得水果 2 。
- 免费获得水果 2 。
- 花 1 个金币购买水果 3 ,然后免费获得水果 4 。
- 免费获得水果 4 。
购买所有水果需要最少花费 2 个金币。

题目解释

1.需要买下所有水果,每个水果有一个价格prices[i],下标从1-n

2.买下第 i 个水果,后面的 i 个水果都可以免费获得,即 下标从i+1到2*i的水果都是可以免费获得的。

3.可以购买免费的水果j,为了免费获得后面的j个水果。

思路引入

1.当前的水果i,那么下一个要买的水果是i+1到2i+1中的一个,因为2i+1位置的水果必须要买,也可以选择购买i+1到2i+1中的一个免费获得2*i+1位置的水果

2.必须从后往前递推,因为从前往后递推的话,到一个当前位置i,不知道之前的水果哪个是买的哪个是免费获得的。

3.如果2*i>=n,然后购买了水果i,那么后面全部的水果都可以全部免费得到。

解题步骤

1.定义dp数组

dp[i]表示买第i-n个水果所需要花费的最少金币数。

2.递推公式:

因为买了i,下一个水果应该在i+1到2i+1中选一个,所以应该在i+1到2i+1中选一个j,此时dp[i] = dp[j]+prices[i-1] (因为下标从1开始,prices还是普通的从0开始的数组,所以要i-1)

因为是要求需要花费的最少金币数,所以要找到一个j,使得最小的dp[i]的值最小。

 即

ans = 999999
for j in range(i+1,2*i+2):
    ans = min(dp[j]+prices[i-1])
dp[i] = ans

可以用切片简化为寻找一个最小的dp[j],再加上prices[i-1]的值,就等于dp[i]

dp[i] = min(dp[i+1:2*i+2])+prices[i-1]

需要注意的是,当2*i>=n时,买了水果i可以不用管后面的所有水果,此时

dp[i] =prices[i-1]

3.初始化

因为在遍历过程中,从n-1的水果都遍历到了,所以不用另外初始化

4.遍历顺序

因为dp[i]的值依赖于dp[i+1]到dp[2*i+1],所以遍历顺序应该从后往前遍历

5.打印dp数组

对于 prices = [3,1,2],dp数组如下

[0, 0, 0, 2]   对于第i=3,i*2>=n,买第3个水果,dp[3] = prices[3-1]
[0, 0, 1, 2]   对于第i=2,i*2>=n,买第2个水果,dp[2] = prices[2-1]
[0, 4, 1, 2]   对于第i=1,在dp[i+1,2*i+2]中选择最小值,dp[1] = min(dp[i+1:2*i+2])再加上prices[1-1]

完整代码

class Solution:
    def minimumCoins(self, prices: List[int]) -> int:
        n = len(prices)
        dp = [0]*(n+1)
        for i in range(n,0,-1):
            if i*2>=n:
                dp[i] = prices[i-1]
            else:
                dp[i] = min(dp[i+1:2*i+2])+prices[i-1]
        return dp[1]

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值