算法之动态规划(爬楼梯)

动态规划的概念

通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。

动态规划的基本思想

若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。 通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量: 一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。 这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。

动态规划三要素

1>最优子结构
2>边界
3>状态转移公式

动态规划例子

题目:

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

    比如,每次走1级台阶,一共走10步,这是其中一种走法。我们可以简写成 1,1,1,1,1,1,1,1,1,1。

思路分析:
首先,我们先想一个问题,如果只差最后一步有几种到达10层的方法
9 + 1
8 + 2
一种是从8层去十层,一种是九层到十层。
那么F(10) = F(9)+F(8);
递归过去
F(9) = F(8)+F(7)….
F(9),F(8)就是F(10)的最优子结构
F(1) = 1 ,F(2) = 2就是边界
F(n) = F(n-1)+F(n-2)就是状态转移方程
所以得到第一种写法:

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

但是这样的递归关系有重复的步骤。
可以用一个HashMap来记重
于是有了第二种写法:

public static int getways(int n,HashMap map) {
        if(n < 1) {
            return 0;
        }
        if(n == 1) {
            return 1;
        }
        if(n == 2) {
            return 2;
        }
        if(map.containsKey(n)) {
            return map.get(n);
        }else {
            int value = getways(n-1) + getways(n-2);
            map.put(n, value);
            return value;
        }
    }

然后思路反转,既然能递归,那么我们能不能从F(1)迭代到F(10)呢?
第三种方法:

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

这样的时间复杂度只有o(n),显然更加好。

你可能感兴趣的:(Java,数据结构)