leetcode-DP入门

1.climb stair问题

n层楼梯,一次可以爬一层或两层,问爬到n层又几种方法

Summary

You are climbing a stair case. It takes n steps to reach to the top.

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

Solution


Approach 1: Brute Force

Algorithm

In this brute force approach we take all possible step combinations i.e. 1 and 2, at every step. At every step we are calling the function climbStairsclimbStairs for step 11 and 22, and return the sum of returned values of both functions.

climbStairs(i,n)=(i + 1, n) + climbStairs(i + 2, n)climbStairs(i,n)=(i+1,n)+climbStairs(i+2,n)

where ii defines the current step and nn defines the destination step.

public class Solution {
    public int climbStairs(int n) {
        return climb_Stairs(0, n);
    }
    public int climb_Stairs(int i, int n) {
        if (i > n) {
            return 0;
        }
        if (i == n) {
            return 1;
        }
        return climb_Stairs(i + 1, n) + climb_Stairs(i + 2, n);
    }
}

Complexity Analysis

  • Time complexity : O(2^n)O(2n). Size of recursion tree will be 2^n2n.

    Recursion tree for n=5 would be like this:

    Climbing_Stairs

  • Space complexity : O(n)O(n). The depth of the recursion tree can go upto nn.


Approach 2: Recursion with Memoization

Algorithm

In the previous approach we are redundantly calculating the result for every step. Instead, we can store the result at each step in memomemo array and directly returning the result from the memo array whenever that function is called again.

In this way we are pruning recursion tree with the help of memomemo array and reducing the size of recursion tree upto nn.

public class Solution {
    public int climbStairs(int n) {
        int memo[] = new int[n + 1];
        return climb_Stairs(0, n, memo);
    }
    public int climb_Stairs(int i, int n, int memo[]) {
        if (i > n) {
            return 0;
        }
        if (i == n) {
            return 1;
        }
        if (memo[i] > 0) {
            return memo[i];
        }
        memo[i] = climb_Stairs(i + 1, n, memo) + climb_Stairs(i + 2, n, memo);
        return memo[i];
    }
}

Complexity Analysis

  • Time complexity : O(n)O(n). Size of recursion tree can go upto nn.

  • Space complexity : O(n)O(n). The depth of recursion tree can go upto nn.
     


Approach 3: Dynamic Programming

Algorithm

As we can see this problem can be broken into subproblems, and it contains the optimal substructure property i.e. its optimal solution can be constructed efficiently from optimal solutions of its subproblems, we can use dynamic programming to solve this problem.

One can reach ith step in one of the two ways:

  1. Taking a single step from (i−1)th step.

  2. Taking a step of 22 from (i−2)th step.

So, the total number of ways to reachith is equal to sum of ways of reaching (i−1)th step and ways of reaching (i−2)th step.

Let dp[i]dp[i] denotes the number of ways to reach on i^{th}ith step:

dp[i]=dp[i-1] + dp[i-2]

public class Solution {
    public int climbStairs(int n) {
        if (n == 1) {
            return 1;
        }
        int[] dp = new int[n + 1];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

 

4 / 7

Complexity Analysis

  • Time complexity : O(n)O(n). Single loop upto nn.

  • Space complexity : O(n)O(n). dpdp array of size nn is used.
     


Approach 4: Fibonacci Number

Algorithm

In the above approach we have used dpdp array where dp[i]=dp[i-1]+dp[i-2]dp[i]=dp[i−1]+dp[i−2]. It can be easily analysed that dp[i]dp[i] is nothing but i^{th}ith fibonacci number.

Fib(n)=Fib(n-1)+Fib(n-2)Fib(n)=Fib(n−1)+Fib(n−2)

Now we just have to find n^{th}nth number of the fibonacci series having 11 and 22 their first and second term respectively, i.e. Fib(1)=1Fib(1)=1 and Fib(2)=2Fib(2)=2.

public class Solution {
    public int climbStairs(int n) {
        if (n == 1) {
            return 1;
        }
        int first = 1;
        int second = 2;
        for (int i = 3; i <= n; i++) {
            int third = first + second;
            first = second;
            second = third;
        }
        return second;
    }
}

Complexity Analysis

  • Time complexity : O(n)O(n). Single loop upto nn is required to calculate n^{th}nth fibonacci number.

  • Space complexity : O(1)O(1). Constant space is used.
     


Approach 5: Binets Method

Algorithm

public class Solution {
    public int climbStairs(int n) {
        int[][] q = {{1, 1}, {1, 0}};
        int[][] res = pow(q, n);
        return res[0][0];
    }
    public int[][] pow(int[][] a, int n) {
        int[][] ret = {{1, 0}, {0, 1}};
        while (n > 0) {
            if ((n & 1) == 1) {
                ret = multiply(ret, a);
            }
            n >>= 1;
            a = multiply(a, a);
        }
        return ret;
    }
    public int[][] multiply(int[][] a, int[][] b) {
        int[][] c = new int[2][2];
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
            }
        }
        return c;
    }
}

Complexity Analysis

  • Time complexity : O(\log n)O(logn). Traversing on \log nlogn bits.

  • Space complexity : O(1)O(1). Constant space is used.

Proof of Time Complexity:

Let's say there is a matrix MM to be raised to power nn. Suppose, nn is the power of 2. Thus, n = 2^in=2i, i\in\mathbb{N}i∈N, where \mathbb{N}N represents the set of natural numbers(including 0). We can represent in the form of a tree:

Climbing Stairs


Approach 6: Fibonacci Formula

Algorithm

public class Solution {
    public int climbStairs(int n) {
        double sqrt5=Math.sqrt(5);
        double fibn=Math.pow((1+sqrt5)/2,n+1)-Math.pow((1-sqrt5)/2,n+1);
        return (int)(fibn/sqrt5);
    }
}

Complexity Analysis

  • Time complexity : O(\log n)O(logn). powpow method takes \log nlogn time.

  • Space complexity : O(1)O(1). Constant space is used.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值