题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
问题分析
这是一道典型的动态规划题目,依据动态规划思想很好解决。
动态规划
通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。
1.求解思路
- 阶段划分
按照问题的时间或空间特征,把问题分为若干个阶段。在划分阶段时,注意划分后的阶段一定要是有序的或者是可排序的,否则问题就无法求解。 - 确定状态
将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。 - 转移方程
因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。所以如果确定了决策,状态转移方程也就可写出。但事实上常常是反过来做,根据相邻两段各状态之间的关系来确定决策。 - 边界条件
给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。
2.实列总结
- 斐波那契数列(Fibonacci polynomial)
- 背包问题
背包问题(Knapsack problem)是一种组合优化的NP完全问题。
问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。 - 最大递增子序列问题
问题描述:给出一个数列A,求A的一个长度最大的子数列B,使得B是一个递增数列。 - 最长公共子序列问题
- 股票收益最大化
本题解答
- n=0, f(0) = 0;
- n=1, f(1) = 1;
- n=2, f(2) = 2;
- n=3, f(3) = f(2) + f(1);
- ……依此类推
- n = n, f(n) = f(n-1) + f(n-2);
因为内存限制,不考虑用递归方式求解,用循环——数组或者循环——非数组形式求解。
int jumpFloor(int number) {
if(number<=0) return 0;
int *a = new int[number+1];
a[1] = 1;
a[2] = 2;
for(int i=3;i<=number;++i)
{
a[i] = a[i-1]+a[i-2];
}
return a[number];
}
本题变形
1.问题描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
2.问题分析
相较于上一题,从每次的一步、两步两种情况变成了1…n种情况。
- 分阶段思考:
- 转移方程
由上面可以分析得到转移方程为:
f(n) = f(n-1)+f(n-2)+f(n-3)+…+f(1)+1
其中“1”代表一次跳满台阶。
- 代码实现
int jumpFloorII(int number) {
if(number<=0) return 0;
int *a = new int[number+1];
a[0] =0;
a[1] =1;
for(int i=2;i<=number;++i)
{
int sum =0;
for(int j=i-1;j>0;--j)
{
sum +=a[j];
}
a[i] = sum+1;
}
return a[number];
}
- 结果分析