四步解决动态规划–绪论
抽象四步
- 识别出递推问题。
如果问题具备规模性,也就是说问题的答案与更小问题的答案有关系,那么问题可以通过递推的方式进行求解。虽然,一般说动态规划时,要求具备最优子结构和重叠子问题两个特点,但是,正如前文所说,动态规划仅仅是递推问题的一种特例而已。 - 定义递推问题。
要求解递推问题,必须要写出递推公式,那么,就必须要确定递推中的每一项究竟表示什么。对于下面的抽象递推公式,我们要明确 a n a_n an表示什么,问题的规模变量 n n n又对应什么。
a n = f ( a n − 1 , a n − 2 , . . . , a 0 ) a_n =f(a_{n-1},a_{n-2},...,a_0) an=f(an−1,an−2,...,a0) - 写出递推公式。
根据题意,写出递推公式,确定出 f f f.可以从最简单的问题开始写,逐步向后推,也可以从逐步减小问题规模向前推。 - 按照递推问题的三种解题方式解题。
上一篇博文已经说明,存在三种通用的方式解决递推问题:
· 递归法,也就是暴力搜索
· 备忘法,也就是递归的时候将子问题的结果记录下来。
· 制表法,也就是按照从小到达,自下而上的递推出大问题的答案。
2. 爬楼梯-四步解题
leetcode 70 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
简单分析:
显然这个问题是与台阶的总数目相关的,如果从最开始到现在站的台阶的方法数知道,那么从站的台阶往后一个台阶或者2个台阶的方法总数我们也就能够知道了。
1=1
2=1+1
2=2
3=1+1+1
3=1+2
3=2+1
a
3
=
a
2
+
a
1
a_3 = a_2 + a_1
a3=a2+a1
4=1+1+1+1
4=1+1+2
4=1+2+1
4=2+2
4=2+1+1
a
4
=
a
3
+
a
2
a_4=a_3+a_2
a4=a3+a2
步骤 | 内容 | 结论 |
---|---|---|
1 | 是否是递推问题? | 是 |
2 | 确定递推问题 | a n a_n an:台阶数为 n n n时,爬到楼梯的方法总数 |
3 | 递推公式 | a n = a n − 1 + a n − 2 ∗ 2 a_n = a_n-1+a_{n-2}*2 an=an−1+an−2∗2 |
- 求解
//递归式求解
/*** 超出时间限制,最后执行输入45 ***/
int f1(int n)
{
if(n==1) return 1;
if(n==2) return 2;
return f1(n-1)+1,f1(n-2);
}
//备忘求解
/***
执行用时:0 ms, 在所有 C 提交中击败了100.00%的用户
内存消耗:5.6 MB, 在所有 C 提交中击败了5.88%的用户
通过测试用例:
45 / 45
***/
int memo[50]={0};
int f2(int n)
{
if(n==1)return 1;
if(n==2)return 2;
if(memo[n-1]==0)memo[n-1]=f2(n-1);
if(memo[n-2]==0)memo[n-2]=f2(n-2);
return memo[n-1] + memo[n-2];
}
//制表求解(自下而上递推)
/***
执行用时:0 ms, 在所有 C 提交中击败了100.00%的用户
内存消耗:5.4 MB, 在所有 C 提交中击败了60.75%的用户
通过测试用例:45 / 45
***/
int f3(int n)
{
if(n<3)return n;
int fn2 = 1, fn1 = 2;//fn2:fn-2, fn1:fn-1
for(int i=3; i<=n; i++)
{
int f = fn1 + fn2;
fn2 = fn1;
fn1 = f;
}
return fn1;
}