动态规划解决跳台阶问题
- 前言
- 过程
- 最后
前言
- 动态规划是一种把原问题分解为相对简单的一系列子问题的方式进行求解的方法。动态规划通常可以用于解决有重叠子问题和最优子结构的问题。
- 在LeetCode上有非常多关于动态规划的问题,很有逻辑性和技巧性,这次以一道很经典的跳台阶问题来学习动态规划。
过程
leetCode原题:一只青蛙一次可以跳一个台阶,也可以跳两个台阶,求该青蛙跳上10级台阶共有多少种跳法。
-
首先当我们解析一下其过程,就会发现这题不难:
- 当有一级台阶时,只有一种跳台阶的方式。
- 当有两级台阶时,可以选择一级一级跳台阶,也可以一次性跳两级台阶,就有两种跳台阶方式。
- 当有三级台阶时,需要先跳到一级台阶再跳两个台阶,也可以跳到二级台阶再跳一个台阶,相当于f(1)+f(2)方式。
- 当有四级台阶时,需要先跳到二级台阶再跳两个台阶,也可以跳到三级台阶再跳一个台阶,相当于f(2)+f(3)方式。
- …
- 当有十级台阶时,需要先跳到8级台阶再跳两个台阶,也可以跳到9级台阶再跳一个台阶,相当于f(8)+f(9)方式。
-
上面的过程就是动态规划的穷举分析法。
-
然后我们可以发现当只有一级或者两级台阶时,跳的方式是可以确定的,就只有一种和两种。这就是动态规划的确定边界
-
后面的不管是3级台阶还是10级台阶,其跳台阶方式的都可以用f(x) = f(x-1)+f(x-2)方式进行计算得出结果。找到规律,确定其最优子结构函数。
-
那么f(x) = f(x-1)+f(x-2)就是动态规划的状态转移方式。
-
最后我们就用代码实现:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26/** * 动态规划: * * @AUTHOR ZRH * @DATE 2021/4/22 */ public class Test1 { public static void main(String[] args) { // 只有一级或两级台阶就直接返回结果 if (1 == y) { return 1; } if (2 == y) { return 2; } // a和b为当前台阶的前两次台阶计算结果 int a = 1, b = 2, result = 0; for(int i = 3; i <= y; i++){ result = a + b; a = b; b = result; } return result; } }
- 这里是由一级,二级,,,十级台阶计算方式,是由自底向上的方式进行计算。其时间复杂度是O(n)。
- 这道题除了动态规划以外,还可以用递归的方式进行解决,只是时间复杂度是O(2^n)。但也可以优化为O(n)。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25/** * 动态规划: * * @AUTHOR ZRH * @DATE 2021/4/22 */ public class Test1 { public static void main(String[] args) { Integer num = 10; System.out.println("test1 : " + test1(num)); } /** * 暴力递归解决 */ private static Integer test1(Integer y) { if (1 == y) { return 1; } if (2 == y) { return 2; } return test1(y - 1) + test1(y - 2); } }
- 上面这种方式是自顶向下的方式进行计算,每增加一个台阶就相当于增加一个f(x)=f(x-1)+f(x-2)计算方法,所以时间复杂度是O(2^n)。
- 针对上面这种情况,可以发现整个递归过程有大量的重复计算,如果把计算结果进行保存下来就可以减少其重复计算的时间消耗。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31/** * 动态规划: * * @AUTHOR ZRH * @DATE 2021/4/22 */ public class Test1 { public static void main(String[] args) { Integer num = 10; System.out.println("test2 : " + test2(num)); } /** * 优化递归方式 */ private final static Map<Integer, Integer> map = new HashMap<>(); private static Integer test2(Integer y) { if (1 == y) { return 1; } if (2 == y) { return 2; } if(map.containsKey(y)){ return map.get(y); } int value = test1(y - 1) + test1(y - 2); map.put(y, value); return value; } }
- 上述代码使用了map缓存了每次计算的结果,减少了大量重复计算的消耗,其时间复杂度是O(n)。
最后
- 动态规划的解题思路:
- 穷举分析
- 确定边界
- 最优子结果
- 状态转移方程
- 代码实现
- 针对上述过程,动态规划有个可参考的框架:
复制代码
1
2
3
4
5
6
7
8
9
10dp[0][0][...] = 边界值 for(状态1 :所有状态1的值){ for(状态2 :所有状态2的值){ for(...){ //状态转移方程 dp[状态1][状态2][...] = 求最值 } } }
- 如果有什么地方写的不对的,欢迎指出,我确认后会加以改正 -_-
最后
以上就是典雅烧鹅最近收集整理的关于动态规划解决跳台阶问题记录一下的全部内容,更多相关动态规划解决跳台阶问题记录一下内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复