代码随想录算法训练营Day 45 || 70. 爬楼梯 、322. 零钱兑换 、279.完全平方数

70. 爬楼梯 (进阶) 

动态规划解法:

  1. 定义状态

    • dp[i] 表示到达第 i 阶楼梯的方法总数。
  2. 初始条件

    • dp[1] = 1,只有一种方法爬一阶楼梯(即直接爬一阶)。
    • dp[2] = 2,有两种方法爬两阶楼梯(一次爬两阶或分两次每次爬一阶)。
  3. 状态转移方程

    • dp[i] = dp[i - 1] + dp[i - 2],可以从第 i-1 阶爬一阶到达,或者从第 i-2 阶爬两阶到达。
  4. 计算方法

    • 3n 遍历,应用状态转移方程计算每一阶的方法数。
  5. 优化

    • 由于每次计算只依赖前两个状态,可以不使用数组来保存所有状态,只需使用两个变量来保存前两个状态,进一步降低算法的空间复杂度。
class Solution:
    def climbStairs(self, n: int) -> int:
        if n == 1:
            return 1
        first, second = 1, 2
        for i in range(3, n + 1):
            third = first + second
            first, second = second, third
        return second

在这个代码中,firstsecond 分别代表达到当前楼梯前两阶的方法数。循环开始时,firstsecond 分别初始化为达到第一阶和第二阶的方法数。然后,通过迭代更新这两个变量,直到计算出达到第 n 阶的方法数。

 322. 零钱兑换  

"322. 零钱兑换"问题是一个经典的动态规划问题,类似于完全背包问题。在这个问题中,你需要找到最少的硬币数目,使得它们的总金额等于给定的数额。如果没有任何一种硬币组合能组成总金额,返回 -1

问题描述如下:

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1

示例:

输入: coins = [1, 2, 5], amount = 11
输出: 3 
解释: 11 = 5 + 5 + 1

在这个问题中,硬币的面额和数量是无限的,类似于完全背包问题中物品的无限性。

解题步骤

  1. 定义状态

    • 创建一个数组 dp,其中 dp[i] 表示组成金额 i 所需的最少硬币个数。
  2. 初始化状态

    • 初始化 dp[0] = 0,因为组成金额0不需要任何硬币。
    • 其他的 dp[i] 初始化为一个大数,表示无法达到的状态(例如 amount + 1 或者 float('inf'))。
  3. 状态转移方程

    • 遍历每一种硬币面额 coin,对于每个金额 i 从 coin 到 amount,更新 dp[i] 的值:
    • dp[i] = min(dp[i], dp[i - coin] + 1)。这里的 dp[i - coin] + 1 表示当前金额减去硬币面额后的最少硬币数加上这一枚硬币。
  4. 迭代更新 dp 数组

    • 对于 coins 中的每个硬币,我们正序遍历 dp 数组从 coin 到 amount
  5. 返回结果

    • 如果 dp[amount] 没有被更新过,说明没有合适的硬币组合能组成总金额,返回 -1
    • 否则,返回 dp[amount]

代码实现

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [float('inf')] * (amount + 1)
        dp[0] = 0
        
        for coin in coins:
            for i in range(coin, amount + 1):
                dp[i] = min(dp[i], dp[i - coin] + 1)
        
        return dp[amount] if dp[amount] != float('inf') else -1

在这段代码中,我们通过不断迭代更新 dp 数组来找出达到每个金额所需的最少硬币数量。最终 dp[amount] 将给出组成总金额所需的最少硬币数。如果 dp[amount] 仍然是初始化的大数值,意味着没有解,因此返回 -1

 279.完全平方数  

“279. 完全平方数” 是一个经典的动态规划问题。问题描述如下:

给定一个正整数 n,找到若干个完全平方数(例如,1, 4, 9, 16, …)使得它们的和等于 n。你需要找到组成和为 n 的完全平方数的最小数量。

示例:

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

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

解题步骤

  1. 定义状态

    • 创建一个数组 dp,其中 dp[i] 表示组成数字 i 所需的最小完全平方数的数量。
  2. 初始化状态

    • dp[0] = 0,因为数字0不需要任何平方数。
    • 其他 dp[i] 初始化为 i,因为最坏的情况是每次加1,所以最多需要 i 个数。
  3. 状态转移方程

    • 对于每个 i 从 1 到 n,计算所有小于或等于 i 的平方数 j*j,并更新 dp[i] 的值:
    • dp[i] = min(dp[i], dp[i - j*j] + 1)。这里 dp[i - j*j] + 1 表示当前数字减去一个完全平方数后的最小平方数数量加上这一个完全平方数。
  4. 计算顺序

    • 正序遍历每个数字 i,确保在计算 dp[i] 之前,所有小于 i 的 dp 值都已经被计算过。
  5. 优化空间复杂度

    • 实际上,没有必要优化空间复杂度,因为我们需要所有之前的状态来计算当前状态。

代码实现

class Solution:
    def numSquares(self, n: int) -> int:
        dp = [float('inf')] * (n+1)
        dp[0] = 0
        
        # 预计算所有可能用到的平方数
        squares = [i*i for i in range(1, int(n**0.5)+1)]
        
        for i in range(1, n+1):
            for square in squares:
                if i >= square:
                    dp[i] = min(dp[i], dp[i-square] + 1)
        
        return dp[n]

在这段代码中,dp 数组用来存储达到每个数字所需的最小平方数数量。我们首先计算出所有可能用到的平方数以避免重复计算。然后通过动态规划的方法,考虑减去每个平方数之后的状态,找到最小的可能值。最终 dp[n] 将给出组成数字 n 所需的最小完全平方数数量。如果没有平方数可以组成 n,这个方法会返回 dp[n] 为 float('inf'),但在初始化的时候我们已经保证了每个数都能被表示成若干个平方数的和。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值