leetcode 322 零钱兑换(动态规划,完全背包,打表法)

题目:
在这里插入图片描述
我们利用 打表法来找出转移方程:

方阵中每一个格子的值计算过程如下所示:
行表示硬币的面值,列表示金额amnout的数量;
我们对首先对每个格子的初始化值都为amnout + 1;
每一行表示目前只能取到0到i个硬币,后面面值的硬币先不考虑;
对于dp[i][j](即每个格的值所代表的含义:表示在凑出当前金额j所需要0到i个硬币的最小数量;
很容易理解,我们的第一列值都应该为0;凑出金额0需要0枚硬币;
在这里插入图片描述
下面我们手动计算一下第二行,即目前只能取到面值为0和面值为1的硬币;
在这里插入图片描述
手动计算第三行:
在这里插入图片描述
在计算的过程中,我们可以得出状态转移方程:

if j >= coins[i -1]:
    dp[i][j] = min(dp[i - 1][j], dp[i][j - coins[i - 1]] + 1)
else:
    dp[i][j] = dp[i -1][j]

因此,二维dp代码如下:

class Solution:
    def coinChange(self, coins, amount):

        dp = [[amount + 1] * (amount + 1) for i in range(len(coins) + 1)]

        for i in range(len(coins) + 1):


            dp[i][0] = 0
        # print(dp)


        for i in range(1,len(coins) + 1):

            for j in range(0, amount + 1):

                if j >= coins[i -1]:

                    dp[i][j] = min(dp[i - 1][j], dp[i][j - coins[i - 1]] + 1)
                else:
                    dp[i][j] = dp[i -1][j]


        if dp[len(coins)][amount] <= amount:
            return dp[len(coins)][amount]
        else:
            return -1

下面进行简化为一维dp:
这时候如果我们理解了完全背包问题,就很容易理解二维到一维dp的压缩过程
二维的状态转移方程:

if j >= coins[i -1]:
    dp[i][j] = min(dp[i - 1][j], dp[i][j - coins[i - 1]] + 1)
else:
    dp[i][j] = dp[i -1][j]

如果压缩为一维度,我们可以把第一维度压缩了,即变成如下的方程:
dp[j] = min(dp[j], dp[j - coins[i - 1]] + 1])
变成上述形式其实就是一个先后计算的问题(并且也关系到硬币数量可以取无限次的情况)
下面我们认真分析:
在未更新dp[j](dp[i][j])之前,dp[j]表示dp[i - 1][j]
因此,dp[i - 1][j] 可以表示为dp[j]
而dp[i][j - coins[i - 1]]中j - coins[i - 1]的值是小于j的,因此是已经计算(更新)过的
所以,dp[i][j - coins[i - 1]]可以表示为dp[j - coins[i - 1]]

因此,状态转移方程如下所示:
dp[j] = min(dp[j], dp[j - coins[i - 1]] + 1])

一维dp代码如下所示:

class Solution:
    def coinChange(self, coins, amount):

        #一维dp
        dp = [amount + 1] * (amount + 1)

        dp[0] = 0

        for i in range(1, len(coins) + 1):

            for j in range(0, amount + 1):

                if j >= coins[i - 1]:

                    dp[j] = min(dp[j], dp[j - coins[i - 1]] + 1)

                
        if dp[amount] <= amount:

            return dp[amount]
            
        else:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值