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

70. 爬楼梯 (进阶)

题目链接:LeetCode - The World's Leading Online Programming Learning Platform

解法:

问题改为:一步一个台阶,两个台阶,三个台阶,.......,直到 m个台阶。问有多少种不同的方法可以爬到楼顶n呢?

1阶,2阶,.... m阶就是物品,楼顶n就是背包。每一阶可以重复使用,例如跳了1阶,还可以继续跳1阶。

问跳到楼顶有几种方法其实就是问装满背包有几种方法。这就是一个完全背包问题了!而且是一个排列问题。

解法与之前的题目一样,所以不赘述了。

边界条件:无

时间复杂度:O(nm),m是每次可以跳1,2,...m步

空间复杂度:O(n)

class Solution(object):
    def climbStairs(self, n):
        dp = [0] * (n+1)
        dp[0] = 1
        for j in range(1, n+1):
            for step in [1, 2]:
                if j >= step:
                    dp[j] += dp[j-step]
        return dp[n]

322. 零钱兑换 

题目链接:https://leetcode.com/problems/coin-change

解法:

每种硬币的数量是无限的,可以看出是典型的完全背包问题。

1. 确定dp数组以及下标的含义

dp[j]:凑足总额为j所需钱币的最少个数为dp[j]

2. 确定递推公式

凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j](考虑coins[i])

所以dp[j] 要取所有 dp[j - coins[i]] + 1 中最小的。

递推公式:dp[j] = min(dp[j - coins[i]] + 1, dp[j]);

3. dp数组如何初始化

首先凑足总金额为0所需钱币的个数一定是0,那么dp[0] = 0;

考虑到递推公式的特性,dp[j]必须初始化为一个最大的数,否则就会在min(dp[j - coins[i]] + 1, dp[j])比较的过程中被初始值覆盖。

所以下标非0的元素都是应该是最大值。

4. 遍历顺序

本题求钱币最小个数,那么钱币有顺序和没有顺序都可以,都不影响钱币的最小个数

所以本题并不强调集合是组合还是排列。

边界条件:无

时间复杂度:O(n * amount),其中 n 为 coins 的长度

空间复杂度:O(amount)

class Solution(object):
    def coinChange(self, coins, amount):
        # 由于求最小数量,所以初始化为无穷大
        dp = [float("inf")] * (amount+1)
        # amount可以取0
        dp[0] = 0
        for c in coins:
            for j in range(c, amount+1):
                # 不是无穷大才可以进行状态转移
                if j - c != float('inf'):
                    dp[j] = min(dp[j], dp[j-c]+1)
        if dp[amount] == float('inf'):
            return -1
        return dp[amount]

279.完全平方数

题目链接:https://leetcode.com/problems/perfect-squares

解法:

这道题和上一题差不多。

需要注意的地方有:

1. 加入的数字是 i^2,而不是i;

2. 如果不能表示为完全平方数之和,那就返回0,而不是-1。这点和上一题不同。

边界条件:无

时间复杂度:O(n * √n)

空间复杂度:O(n)

class Solution(object):
    def numSquares(self, n):
        m = int(n ** 0.5)
        dp = [float('inf')] * (n+1)
        dp[0] = 0
        for i in range(1, m+1):
            # 一定要注意这里是 i*i,包括下面也是
            for j in range(i*i, n+1):
                dp[j] = min(dp[j], dp[j-i*i]+1)
        return dp[n]

你可能感兴趣的:(数据结构和算法,算法)