代码随想录算法训练营day45 | 70. 爬楼梯 (进阶),322. 零钱兑换,279.完全平方数

70. 爬楼梯 (进阶)

本题难点在于如何映射到完全背包问题

  • 什么是背包,什么是物品?
    • 1阶,2阶,.... m阶就是物品,楼顶就是背包(容量)。
    • 对应本题:m=2因为可以爬1step或者2steps,可以写成数组形式 temp = [i for i in range(m+1)]; 楼顶就是n(也就是#377. 组合总和 Ⅳ中的target)
  • 注意每一阶可以重复使用,例如跳了1阶,还可以继续跳1阶(也就是上面的temp数组中的元素可以重复使用)。

  • 问跳到楼顶有几种方法其实就是问装满背包有几种方法。

动规五部曲(也可以参考#377. 组合总和 Ⅳ)

  1. 确定dp数组以及下标的含义:dp[i]:爬到有i个台阶的楼顶,有dp[i]种方法
  2. 确定递推公式:dp[i] = dp[i]+dp[i-temp[j]]
  3. dp数组如何初始化:dp[0] = 1
  4. 确定遍历顺序:注意先上1阶再上2阶和先上2阶再上1阶是不同的走法,因此是求排列问题,这样与#377. 组合总和 Ⅳ一样,要先背包后物品的遍历顺序
  5. 打印检查
class Solution(object):
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        dp = [0]*(n+1) 
        dp[0] = 1
        m = 2 #一次最多可以走2阶
        temp = [i for i in range(m+1)]

        for i in range(1, n+1): #先背包
            for j in range(1, len(temp)): #后物品
                if i>= temp[j]:
                    dp[i] = dp[i]+dp[i-temp[j]]
        return dp[n]

322. 零钱兑换

  • 这道题可以相对直观的对应到完全背包问题

  • 与#518. 零钱兑换 II对比理解

动规五部曲:

  1. 确定dp数组以及下标的含义: dp[j]:凑足总额为j所需钱币的最少个数为dp[j]
  2. 递推公式:不考虑coins[i]的情况,那么凑足总额为j的最少个数为dp[j](step1定义); 考虑coins[i]的情况,那么首先凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],然后只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j]。由于要求最少个数,那么这两个取最小 --> dp[j] = min(dp[j], dp[j-coins[i]]+1)
  3. dp数组如何初始化:dp[amount+1)(amount+1)
  4. 确定遍历顺序:由于是求满足条件的最小个数(既不是求组合也不是求排列)
  5. 打印检查
class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        dp = [10001]*(amount+1)
        dp[0] = 0
        
        for i in range(len(coins)):
            for j in range(coins[i], amount+1):
                dp[j] = min(dp[j], dp[j-coins[i]]+1)

        if dp[amount] == 10001:
            return -1
        return dp[amount]

279.完全平方数

  • 这道题跟#322. 零钱兑换非常相似,区别在于#322给定了coins数组,这道题需要自己先写出来要处理的数组temp。

  • 根据题目要求,temp数组就是包含小于n的所有Perfect Squares。

  • e.g,n = 12, then temp = [1, 4, 9]

class Solution(object):
    def numSquares(self, n):
        """
        :type n: int
        :rtype: int
        """
        temp = []
        for i in range(1, n):
            if i**2 <= n:
                temp.append(i**2)
        # print(temp)

        if n == 1:
            return 1

        dp = [10001]*(n+1)
        dp[0] = 0
        for i in range(len(temp)):
            for j in range(temp[i], n+1):
                dp[j] = min(dp[j], dp[j-temp[i]]+1)
        return dp[n]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值