Algorithm Review: A Reflection from the stairs problem Fibonacci number recursively, to achieve dynamic programming

Problems lead:
leetcode No.70

If it does not start when such practice:

Consider
not work, then consider the following 1. Violence can solve
2. Because the problem is more complicated then compare around to look at the basic situation of mathematical induction summarized in general considered
3. find logic to find the most recent iteration of sub-problems , that is, to find the problem in part repeated
- consider using recursion or dynamic programming

Recursion

1. The most common stupid recursive O (2 ^ n) and may lead to StackOverflow

// 方法一:直接递归  
// 但是这道题有点和斐波那契数列稍稍不符合的地方是 f0=0 而数列中f0=1;
class Solution {
    public int climbStairs(int n) {
          
         if(n == 0) { //不同处 f0=0,它有点点不符合斐波那契数列的思想 而数列中f0=1;
             return 0;
         }   
         if(n == 1) {
            return 1;
         }
         if(n == 2) {
          	return 2;
         }
            return  climbStairs(n-2) + climbStairs(n-1); 
         }  
    }

2. plus an array of recursive buffer (predecessors trees descendants cool LOL)

//这个方法是可以的!! 但是只是适用于在输入44之前的数
// 方法二:记忆化递归 有缓存的思想 创一个数组 每次把递归的结果记录下来 方便下一次递归使用
//每当函数再次被递归调用时,我们就直接从 memo 数组返回结果。
// 但是这道题有点和斐波那契数列稍稍不符合的地方是 f0=0 而数列中f0=1;
class Solution {
    public int climbStairs(int n) {
         int memo[] = new int[n + 1];//防止递归时 溢出
         if(n == 0) { //不同处 f0=0,它有点点不符合斐波那契数列的思想 而数列中f0=1;
             memo[0] = 0;
             return 0;
         }   
         if(n == 1) {
             memo[1] = 1;
             return 1;
         }
         if(n == 2) {
             memo[2] = 2;
             return 2;
         }
         //接下来 和普通递归不同处是 每次先找缓存里面找我需要的递归式 是否已经在上一步算出来并且缓存了
         if(memo[n] != 0) { //因为java数组默认全部填0  那么我这里如果判断n这个位置不是0 说明已经缓存过 
            return memo[n]; //那就返回即可
         } else { //说明之前没缓存 需要缓存 给后面用 (前人栽树后人乘凉LOL)
            int rst = climbStairs(n-2) + climbStairs(n-1); 
            memo[n] = rst;
            return rst; 
         }  
    }
}

3. The method 2plus using cached recursive hashmap

//这个方法也是可以的!! 但是只是适用于在输入44之前的数
// 方法三:记忆化递归plus 有缓存的思想 创一个数组 每次把递归的结果记录下来 方便下一次递归使用
//每当函数再次被递归调用时,和前一种方法的存储不同,前一种我们是从 数组memo[] 返回结果。 而现在可以使用hashmap(好处是使用它内部的查询优化)
// 但是这道题有点和斐波那契数列稍稍不符合的地方是 f0=0 而数列中f0=1;
class Solution {
    public int climbStairs(int n) {
        //  int memo[] = new int[n + 1];//防止递归时 溢出 不用它了 用hashmap
      Map<Integer, Integer> memo = new HashMap<>();
         if(n == 0) { //不同处 f0=0,它有点点不符合斐波那契数列的思想 而数列中f0=1;
             memo.put(0,0);
             return 0;
         }   
         if(n == 1) {
             memo.put(1,1);
             return 1;
         }
         if(n == 2) {
             memo.put(2,2);
             return 2;
         }
         //接下来 和普通递归不同处是 每次先找缓存里面找我需要的递归式 是否已经在上一步算出来并且缓存了
         if(null != memo.get(n)) { //能取到值 说明已经缓存过 
            return memo.get(n); //那就返回即可
         } else { //说明之前没缓存 需要缓存 给后面用 (前人栽树后人乘凉LOL)
            int rst = climbStairs(n-2) + climbStairs(n-1); 
            memo.put(n,rst);
            return rst; 
         }  
    }
}

4. Method four: dynamic programming (bottom-up dynamic programming) or create an array of the results per (sub-problem solutions) recorded programming problem with a parent conveniently
in fact there is a dynamic programming method memorandum (from top-down)

class Solution {
    public int climbStairs(int n) {
        // int dp[] = new int[n+1];//当n取1 这就会报错 所以可以再开大点
        int dp[] = new int[n+2]; 
        if (n == 0) {
            return 0;
        }
        // if (n == 1) {
        //     return 1;
        // }
        // if (n == 2) {
        //     return 2;
        // } //实际可以用下一句代替 因为程序最好单一出口 或者少出口 但是写上的话 易读性更好
        dp[1] = 1;
        dp[2] = 2;
        for(int i = 3; i <= n; i++) {
            dp[i] = dp[i-2] + dp[i-1];
        }
        return dp[n];
    }
}

// / 方法四:动态规划 还是 创一个数组 每次把规划的结果(子问题的解)记录下来 方便下一次父问题使用
 // 但是这道题有点和斐波那契数列稍稍不符合的地方是 f0=0 而数列中f0=1;

The dynamic programming plus (also known as Fibonacci) does not require each array does not require the results (solution of the problem of child) recorded the planning of
each sub-problems exist only during the last three values can be because that solution is a solution of the problem of parent dynamic transformation of the conditions he is constantly changing so the countdown to the second third number certainly can be a solution of the problem of child last a number of

//复习前一天:
// 方法五: 动态规划 但不使用循环 无需记录过程中的数 但是只需要记住最后的三个数即可 因为过程中每次子问题的解是动态变换的  也就是说作为解父问题的条件他是不断变换的 那么到了倒数的第二个第三个数 肯定是可以成为最后一个属的子问题的解 
class Solution {
    public int climbStairs(int n) {
        int rst = 0;
        int f1 = 1;
        int f2 = 2;
        if(n == 0) { //不同处 f0=0,它有点点不符合斐波那契数列的思想 而数列中f0=1;  
             return 0;
         }   
         if(n == 1) {
            return 1;
         }
         if(n == 2) {
          	return 2;
         }
         for(int i = 3; i <= n; i++) {
             rst = f2 + f1;
             f1 = f2;
             f2 = rst;
         }   
         return  rst; 
         }          
    }

What are the differences "recursion" and "iterative" have?

Published 81 original articles · won praise 19 · views 3603

Guess you like

Origin blog.csdn.net/c22cxz/article/details/105030128