动态规划---爬楼梯和硬币组合问题
Posted cplemom
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划---爬楼梯和硬币组合问题相关的知识,希望对你有一定的参考价值。
爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
不难发现,对于要抵达的第n阶台阶,有两种方式可以抵达。
- 在第 (i?1) 阶后向上爬 1 阶。
- 在第 (i-2) 阶后向上爬 2 阶。
得出状态转移方程为
dp[i]=dp[i?1]+dp[i?2]
因此可以得出代码如下:
func climbStairs(n int) int {
if n <= 1 {
return n
}
dp := make([]int, n+1)
dp[1] = 1
dp[2] = 2
for i := 3; i <= n; i++ {
dp[i] = dp[i-1] + dp[i-2]
}
return dp[n]
}
拓展:如果每次我可以爬 1 或 3 或 5 个台阶,这时候有多少种方式可以抵达呢?
原理和每次迈1或2步的时候是一样的,我们就在内部循环可以迈的台阶,进行计算有多少种抵达方式。代码如下:
func climbStairs(n int) int {
if n <= 1 {
return n
}
dp := make([]int, n+1)
step := []int{1, 3, 5}
dp[0] = 1
for i := 1; i <= n; i++ {
for j := 0; j < len(step); j++ {
if i >= step[j] {
dp[i] += dp[i-step[j]]
}
}
}
return dp[n]
}
硬币组合问题
给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。
输入: n = 10
输出:4
解释: 有四种方式可以凑成总金额:
10=10
10=5+5
10=5+1+1+1+1+1
10=1+1+1+1+1+1+1+1+1+1
仔细思考一下,硬币组合问题和爬楼梯问题其实是极其相似的。比如对于给定n = 6的情况下,我们可以从两种情况抵达:
- 从 n = 5 的情况下加一个1分硬币
- 在 n = 1 的情况下加一个5分硬币
乍一看,代码完全应该和上面是一样的嘛!但是如果直接使用上面的代码去计算,会发现最后得出的结果比预料的要多。可以尝试下运行爬楼梯拓展中的代码,计算n=6的情况。为什么?
还是以 n = 6 的情况进行举例
在爬楼梯问题中,先上1步再上5步([1,5]) 和 先上5步再上1步([5,1]) 是2个不同的情况。
在硬币组合问题中,[1,5] 和 [5,1]属于同一个解决方案,都只是使用了一个1分硬币一个5分硬币。
即硬币组合问题中,硬币的排列顺序不会产生不同的解决方案。
那么如何避免硬币的顺序对结果造成的影响呢?答案就是:调换遍历顺序,先遍历硬币,保证在考虑一种硬币的时候没有其它大面额硬币的影响,保证解决方案中始终是小硬币在前大硬币在后。避免重复计算问题,同样在n=6的情况下,解决方案计算只有[1,1,1,1,1,1]和[1,5] 两种。
代码:
func waysToChange(n int) int {
if n <= 1 {
return n
}
dp := make([]int, n+1)
coin := []int{1, 5, 10}
dp[0] = 1
for i := 0; i < len(coin); i++ {
for j := 1; j <= n; j++ {
if j >= coin[i] {
dp[j] += dp[j-coin[i]]
}
}
}
return dp[n]
}
以上是关于动态规划---爬楼梯和硬币组合问题的主要内容,如果未能解决你的问题,请参考以下文章
代码随想录|day38|动态规划part01● 理论基础 ● 509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯