1.动态规划算法

来源:互联网 发布:deepin15 linux 教程 编辑:程序博客网 时间:2024/05/16 11:09

一、问题

有一座高度是10级的楼梯,从下往上走,每跨一步只能向上1级或者2级台阶。求出走到10级一共有多少种走法。

二、分析

走到10级的情况有两种:

从第8级走两步到第10级从第9级走一步到第10级

那么到8级和9级有几种情况呢?

8级:    从第6级走两步到第8级    从第7级走一步到第8级9级:    从第7级走两步到第9级    从第8级走一步到第9级

如果我们假设从0到8有m种走法,从0到9有n种走法,那么0到10级就有m+n种走法。

我们假设求x级台阶走法为函数F(x),那么

F(10) = F(9) + F(8)

那么F(9)、F(8)怎么计算呢?同理不难得出F(x) = F(x-1) + F(x-2),x>=3

F(9) = F(8) + F(7)F(8) = F(7) + F(6)

如果不断枚举下去,总体会是这样的

F(10) = F(9) + F(8)F(9) = F(8) + F(7)F(8) = F(7) + F(6)...F(3) = F(2) + F(1)F(2) = 2F(1) = 1

答案就显而易见了,只要我们从下向上计算就可算出结果了。

F(3) = F(2) + F(1) = 3F(4) = F(3) + F(2) = 5F(5) = F(4) + F(3) = 8..........

接下来什么是动态规划算法呢?

动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推的方式去解决

其中有三个核心的概念:
* 最优子结构
* 边界
* 状态转移公式

最优子结构

F(10) = F(9) + F(8),F(9)、F(8)就是F(10)的最优子结构

边界

F(1)、F(2)可以直接算出,无需继续计算,这就是这个问题的边界,没有边界是无法得出结果的。

状态转移公式

F(x) = F(x-1) + F(x-2); x>=3,这个就是转换不同阶段的状态转移公式,将F(10)的计算转换为了F(9) + F(8)

三、编程实现

1.递归

public static int getCountByRecursion(int x) {        if (x < 1) {            return 0;        }        if (x == 1) {            return 1;        }        if (x == 2) {            return 2;        }        return getCountByRecursion(x -1) + getCountByRecursion(x - 2);    }

2.优化递归

private static HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();    public static int getCountByRecursionMore(int x) {        if (x < 1) {            return 0;        }        if (x == 1) {            return 1;        }        if (x == 2) {            return 2;        }        //如果map包含该值,直接返回        if (map.containsKey(x)) {            return map.get(x);        }        //不包含就继续计算        int value = getCountByRecursionMore(x -1) + getCountByRecursionMore(x - 2);        map.put(x, value);        return value;    }

3.迭代求解

public static int getCountByIteration(int x) {        if (x < 1) {            return 0;        }        if (x == 1) {            return 1;        }        if (x == 2) {            return 2;        }        int a = 1;        int b = 2;        int temp = 0;        for (int i = 3; i < x; i++) {            temp = a + b;            a = b;            b = temp;        }        return temp;    }

主方法

public static void main(String[] args) {        //使用递归        long start1 = System.nanoTime();        log.info("递归算法:" + getCountByRecursion(25) + ";耗时:" + (System.nanoTime() - start1));        //递归优化        long start2 = System.nanoTime();        log.info("递归优化:" + getCountByRecursionMore(25) + ";耗时:" + (System.nanoTime() - start2));        //迭代        long start3 = System.nanoTime();        log.info("迭代:" + getCountByIteration(25) + ";耗时:" + (System.nanoTime() - start3));    }

看下运行的结果,效率的差别非常之大

[01:50:35.465] [INFO] com.kingboy.dynamicprogramming.DynamicMain.main(DynamicMain.java:18) 递归算法:121393;耗时:1826965[01:50:35.468] [INFO] com.kingboy.dynamicprogramming.DynamicMain.main(DynamicMain.java:21) 递归优化:121393;耗时:93255[01:50:35.468] [INFO] com.kingboy.dynamicprogramming.DynamicMain.main(DynamicMain.java:24) 迭代:75025;耗时:8726

完整示例参考github项目algorithm模块下的dynamicprogramming

原创粉丝点击