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

文档讲解:代码随想录

视频讲解:代码随想录B站账号

状态:看了视频题解和文章解析后做出来了

70. 爬楼梯 (进阶)

class Solution:
    def climbStairs2(self, n: int, m: int) -> int:
        dp = [0] * (n+1)
        dp[0] = 1

        for j in range(1, n+1): # 遍历背包
            for i in range(1, m+1): # 遍历物品
                if j-i >= 0:
                    dp[j] += dp[j-i]
        return dp[n]
  • 时间复杂度:O(n*m)
  • 空间复杂度:O(n)

这道题是爬楼梯的进阶版本。

题目从可以爬1或2阶楼梯,变成可以爬 <= m阶楼梯。其实总楼梯数n就是背包总量,m就是物品。

再加上可以重复迈同样级的台阶,所以这道题我们可以用完全背包来解决。

递推公式什么的都没有变化,值得注意的是遍历顺序必须是先背包再物品,这样遍历出的结果是排列不是组合。

322. 零钱兑换

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [float('inf')] * (amount + 1)
        dp[0] = 0

        for coin in coins:
            for j in range(coin, amount + 1):
                dp[j] = min(dp[j], dp[j-coin] + 1)

        if dp[amount] == float('inf'):
            return -1
        return dp[amount]
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(n)

零钱可以重复使用:完全背包。

以下是几个需要注意的点:

  1. 初始化:因为每一步需要判断最小的零钱使用数量,所以除了第一位全部初始为无穷大。第一位是0是因为凑齐0块钱当然不需要任何硬币。
  2. 递推公式:dp[j-coin] 的话是方式数量,这里要加1因为计算的是硬币使用数量而不是方法数量。
  3. 最后返回的时候,如果dp[amount]还是初始化的状态,返回-1证明没有解。
  4. 因为没有要求排列数,所以物品放在外层,背包放在内层。

279.完全平方数

class Solution:
    def numSquares(self, n: int) -> int:
        dp = [float('inf')] * 10001
        dp[0] = 0
        picks = [i**2 for i in range(1,101)]

        for pick in picks:
            for j in range(pick, n+1):
                dp[j] = min(dp[j], dp[j-pick]+1)
        
        if dp[n] == float('inf'):
            return -1
        return dp[n]
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(n)

又是完全背包的应用。这道题中平方数是物品,背包是n。

因为可以重复使用平方数,所以从前往后遍历;因为不需要排列数,所以物品在外循环,背包在内循环。

初始化方面,因为要求最小数量,所以全部初始化为正无穷。除了第一个元素,因为n=0的时候,不需要任何平方数达到。

和上一题一样,递归公式中dp[j-pick]需要+1,因为本题求的不是方案数,而是使用了多少个元素,只要用了这个元素就要+1。

完全独立做出来的题,开心!感觉背包问题掌握地已经很好了。

你可能感兴趣的:(算法,leetcode,职场和发展)