Leetcode 70. 爬楼梯 Java

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

根据题意不难看出这是一道动态规划的题目,只要写出状态转移方程,我们就可以很容易的将其解决,诚然这道题的状态转移方程很简单,那么遇到更难的题目呢?在这里想和大家通过一道例题来分析一下对于这类问题的解决思路。

首先,无从下手的话,我们不妨尝试暴力递归

private int getClimbStairs(int n) {
        if (n == 1) {
            return 1;
        }

        if (n == 2) {
            return 2;
        }
        
        return getClimbStairs(n - 1) + getClimbStairs(n - 2);
    }

这样的代码思路很清晰,在我们的编译器上,也会轻松通过,但是提交到leetcode往往会提示超出时间限制,是因为在n大的时候,递归栈非常之深,每次去递归时间开销很大,所以会抛出超时。那么怎么去在这个思路上去改进呢? 有的同学可能会发现,在递归的时候,不断有重复的递归,比如10会9和8 9会有8和7 这时8已经出现了两次 而相面更小的数字会有更多的重复,那么我们把这些数据存储下来,方便调用不是可以节省开销?

private int[] memo;

    public int climbStairs(int n) {
        memo = new int[n + 1];
        Arrays.fill(memo, -1);
        return getClimbStairs(n);
    }

    private int getClimbStairs(int n) {
        if (n == 1) {
            return 1;
        }

        if (n == 2) {
            return 2;
        }

        if (memo[n] == -1) {
            memo[n] = getClimbStairs(n - 1) + getClimbStairs(n - 2);
        }
        return memo[n];
    }

我们只需要声明一个memo数组,把递归中间过程的值存储下来就好,可以大大的提高效率,这时候提交给leetcode已经可以获得AC了,同时,也得到了这个题目的状态转移方程:memo[i] = memo[i - 1] + memo[i - 2],有了状态转移方程,我们就可以递推的去解决问题。

public int climbStairs(int n) {
        int[] memo= new int[n + 1];
        Arrays.fill(memo, -1);
        
        memo[0] = 1;
        memo[1] = 1;
        
        for (int i = 2; i <= n; i++)
            memo[i] = memo[i - 1] + memo[i - 2];
        
        return memo[n];
    }

这道题目本身很简答,但是遇到困难问题时,希望这种先从上往下记忆化搜索在从下往上层层递推的思路,可以帮到同学们。

看完这道题目之后,有兴趣的同学可以看看64号问题,最小路径和,较之于这道题,稍难一点,不过还是同样的配方同样的味道,有助于加深对于记忆化搜索和动态规划的理解。

猜你喜欢

转载自blog.csdn.net/sinat_33150417/article/details/82791838