研习代码 day39 | 动态规划——完全背包的应用

一、爬楼梯(进阶版)

        1.1 题目

题目描述

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 

每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢? 

注意:给定 n 是一个正整数。

输入描述

输入共一行,包含两个正整数,分别表示n, m

输出描述

输出一个整数,表示爬到楼顶的方法数。

输入示例
3 2
输出示例
3

        1.2 题目链接

        57.爬楼梯

        1.3 解题思路与过程想法

        (1)解题思路

        # 分析:这道题是 70.爬楼梯 的进阶版,对于每次爬楼的最多阶数是个不定值 n。是个典型的背包的排列问题。
        排列问题:1+2+1 和 2+1+1 是两种不同方法
        数组:爬到 i 阶,有 dp[i] 种方法
        递推关系:求组成的方法数——————dp[j] += dp[j-i],
                          求背包装载的最大“价值” ——dp[j] = max(dp[j], dp[j-weight[i]]+value[i])
                          求背包装载的最少“数量” ——dp[j] = min(dp[j], dp[j-weight[i]]+1)
        初始化:求组成的方法数——dp[0] = 1
                       其他值初始化———初始化不影响覆盖的值,求最大-->初始化最小;
                                                                                               求最小-->初始化无穷大值
        遍历顺序:因为是排列问题,所以先遍历背包容量,后遍历物体

        此处 weight[i] 对应着 本次爬楼的阶数
                value[i]   对应着 一次爬楼

        (2)过程想法

        比较经典,思路也比较好想,但需注意是排列问题

        1.4 代码

def up(n,m) -> int:
    # 物品是每次爬的楼梯数,可重复---->完全背包
    # 背包容量 n,物品 1~m
    
    # 数组:爬到 i 阶,有 dp[i] 种方法
    dp = [0] * (n+1)
    
    # 递推关系:dp[j] += dp[j-i]
    
    # 初始化:求方法数,一般初始化 dp[0] = 1,若是0则后续将全是 0 
    dp[0] = 1
    
    for j in range(1,n+1):              # 遍历背包
        for i in range(1,m+1):            # 遍历物体
            if j >= i:
                dp[j] += dp[j-i]
            
    return dp[n]
    
if __name__ == "__main__":
    # 从键盘端一次性连续读取两个数字
    inputs = input()

    # 将输入拆分为两个数字
    num1, num2 = map(int, inputs.split())
    
    print(up(num1,num2))

二、零钱兑换

        2.1 题目

        给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

        计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

        你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11

输出:3
 
解释:11 = 5 + 5 + 1

示例 2:

输入:coins = [2], amount = 3

输出:-1

示例 3:

输入:coins = [1], amount = 0
输出:0

提示:

  • 1 <= coins.length <= 12
  • 1 <= coins[i] <= 2^31 - 1
  • 0 <= amount <= 10^4

        2.2 题目链接

        322.零钱兑换

        2.3 解题思路与过程想法

        (1)解题思路

        # 数组:构成总金额 j 所需的最少硬币数 dp[j]
        # 初始化:初始一个不会覆盖其他值的原始值(求最小,赋无穷大)
        # 递推关系:dp[j] = min(dp[j],dp[j-coin]+1)
        # 完全背包的组合问题:先遍历物体,后遍历背包容量

        (2)过程想法

        针对纯完全背包问题变化不是很大,代码比较好写

        2.4 代码

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        # 完全背包:组合问题

        # 数组:构成总金额 j 所需的最少硬币数 dp[j]
        # 初始化:初始一个不会覆盖其他值的原始值
        dp = [float('inf')] * (amount+1)

        # 递推关系:dp[j] = min(dp[j],dp[j-coin]+1)

        # 初始化 
        dp[0] = 0

        # 举例递推 
        for coin in coins:                  # 遍历物品
            for j in range(coin,amount+1):     # 遍历背包
                dp[j] = min(dp[j],dp[j-coin]+1)

        return dp[amount] if dp[amount] != float('inf') else -1

三、完全平方数

        3.1 题目

        给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

        完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,149 和 16 都是完全平方数,而 3 和 11 不是。

示例 1:

输入:n = 12
输出:3 
解释:12 = 4 + 4 + 4

示例 2:

输入:n = 13
输出:2
解释:13 = 4 + 9

提示:

  • 1 <= n <= 10^4

        3.2 题目链接

        279.完全平方数

        3.3 解题思路与过程想法

        (1)解题思路

        分析:整个题目的变体主要在于“完全平方数”,为了便于遍历,以其需“平方”的数为遍历数。

        # 数组:i 最少可由 dp[i] 个完全平方数组成
        # 初始化:初始一个不会覆盖其他值的原始值(求最小,赋无穷大)
        # 递推关系:dp[j] = min(dp[j],dp[j-i*i]+1)
        # 完全背包的组合问题:先遍历物体,后遍历背包容量

        (2)过程想法

        分析出变化的关系,代码是很好写的

        3.4 代码

class Solution:
    def numSquares(self, n: int) -> int:
        # 完全背包问题-组合问题

        # 数组:i 最少可由 dp[i] 个完全平方数组成
        dp = [float('inf')] * (n+1)

        # 递推关系:dp[j] = min(dp[j],dp[j-i*i]+1)
        # 初始化
        dp[0] = 0

        for i in range(n//2+1):         # 遍历物体
            for j in range(i*i,n+1):    # 遍历背包
                dp[j] = min(dp[j], dp[j - i*i]+1)
        
        # 处理边界情况
        return dp[n] if n != 1 else 1

你可能感兴趣的:(动态规划,算法,数据结构,leetcode,python)