个人博客:The Blog Of WaiterXiaoYY 欢迎来互相交流学习。
今天,开始接触到动态规划问题,现在我对动态规划还没有一个完整的认识,更不用说掌握了,
目前我对动态规划的理解是,
在递归的过程中,我们可能会进行对一个数进行重复递归,这样子就导致时间复杂度呈指数增长,
比如:
在斐波那契数列中,
我们知道 fib(n) = {1, 1, 2, 3 , 5, 8,……}, 这里举个例子,假如我们还不知道 fib(5) 是多少,
如果我们要算 fib(5) ,按照我们递归的思维,我们会这样做:
public int fib(int n) {
if(n == 1 || n == 2)
return 1;
return fib(n - 1) + fib(n - 2);
}
内在流程是这样子的:
其实在运算的过程中,我们重复运算了 fib(3) ,
这时候如果我们想改进算法的话,是不是可以把 fib(3) 的值存起来,
当下面某一次递归到 fib(3) 的时候,我们就可以直接用了?
改进上面那个算法后,长这个样子:
public int fib(int n) {
//判断特殊值
if(n == 1 || n == 2)
return 1;
//申请一个数组来保存算过的值
int []dp = new int[n + 1];
//初始我们前面的值,如果这个值没有初始化是没有规律可行的
dp[1] = 1;
dp[2] = 1;
for(int i = 3; i <= n; i++) {
dp[i] = dp[n - 1] + dp[n - 2];
}
return dp[n];
}
这个就是我初步认识的动态规划。
在leetcode里面有几道类似这样的题,哦不,不是类似,方法感觉就是一模一样的(狗头报命)
一. 青蛙跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n
级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:2
示例 2:
输入:n = 7
输出:21
解题思路
这道题可以分为两part,
第一先是考虑如何求出跳上n级台阶有多少种跳法,
然后再考虑对结果怎么取模;
这道题有个隐藏的条件没有给出来,就是 n == 0
的时候,结果应该是等于1的,
别问我怎么知道的(都是泪)。
跳台阶,有两种方法,一种跳一级,一种跳两级,
当 n == 1
的时候,只有一种跳法,
当 n == 2
的时候,有两种跳法
-
每次都跳一级,跳两次
-
一次跳两级
这时候我们来看看 n == 3
,
n为3的时候,是可以分为子问题进行考虑的,
比如,青蛙是从哪一级跳到第三级的,
有可能是从第一级,直接跳两级,
有可能是从第二级,直接跳一级,
什么?有可能从第一级,每一次跳一级?
这种情况其实就是在第二级跳到第三级。
那青蛙是怎么跳到第二级或者第一级,我们已经讨论过了,
问题拆解完毕!
这样子,我们就知道,跳到 n 级,其实是跟怎么跳到 n - 1
和 n - 2
有关,
那这就是递归的思想,
f(n) = f(n - 1) + f(n - 2)
这就跟上面的斐波那契数列一模一样了。
利用动态规划优化一下,而且这道题用动态规划才能AC,因为递归进去,会超时。
第二步,是需要我们将答案取模,
我一开始这样做的:
return dp[n] % 1000000007;
结果打脸,因为如果针对结果取模的话,数组里面除的数就会超出范围了。
代码
class Solution {
public int numWays(int n) {
//判断特殊值
if(n == 0 || n == 1)
return 1;
//申请一个数组记录已经计算后对应的值
int []dp = new int[n + 1];
//初始值,n == 2情况下的值必须作为初始值
dp[0] = 1;
dp[1] = 1;
dp[2] = 2;
for(int i = 2; i <= n; i++) {
//对结果进行取模后再存入数组
dp[i] = (dp[i - 1] + dp[i -2]) % 1000000007;
}
return dp[n] ;
}
}
二. 爬楼梯问题
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
**注意:**给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
解题思路
这道题和青蛙的题目是一样的,只不过人换成了青蛙,台阶换成了楼梯
直接上代码
代码
class Solution {
public int climbStairs(int n) {
if(n == 0 || n == 1)
return 1;
int []dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
dp[2] = 2;
for(int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i -2];
}
return dp[n] ;
}
}