70. Climbing Stairs

70. Climbing Stairs

Problem Solving - Day 72

ยท

5 min read

Hello, reader ๐Ÿ‘‹๐Ÿฝ ! Welcome to day 72 of the series on Problem Solving. Through this series, I aim to pick up at least one question everyday and share my approach for solving it.

Today, I will be picking up LeetCode's daily challenge problem: 70. Climbing Stairs.


๐Ÿค” Problem Statement

  • It takes n steps to reach the top. Each step can either be climbed in 1 or 2 steps.

  • In how many distinct ways is it possible to climb to the top?

  • E.g.:

    • n = 2 => 2

    • n => 3


๐Ÿ’ฌ Thought Process - Recursion

  • According to the question, if you're at bottom ith step, you can either take 1 step or 2 steps. That is, i + 1 or i + 2 steps can be taken.

  • We can visualise this question in the opposite way as well - climbing from the top nth step to the 0th step. Now this can be done in: n-1 or n-2 steps, i.e. climb down either 1 step down or 2 steps down.

  • In the given example n = 3, there are three ways to climb to the 3rd step: 1 + 1 + 1 steps, 2 + 1 steps or 1 + 2 steps.

  • For calculating ways to reach n = 4, we can make use of the number of ways to climb the 3rd step.

  • n = 4

    • 1 + 1 + 1 + 1

    • 1 + 2 + 1

    • 2 + 1 + 1

    • 1 + 1 + 2

    • 2 + 2

  • Hence every nth step can be solved from the previous calculations.

  • More formally, we can write this as- climbStairs(n) = climbStairs(n-1) + climbStairs(n-2).

    This formula is the same for calculating the nth fibonacci number

  • Hence climbStairs(4) = climbStairs(3) + climbStairs(2) which gives climbStairs(4) = 3 + 2 => 5.

  • But the problem with this approach is that we would be calling the same function repeatedly.

  • For e.g. if n = 6 then n=4 would be called by climbStairs(5) and climbStairs(4), i.e. climbStairs(n-1) and climbStairs(n-2).

  • Hence, we will recursively solve with the above formula f(n) = f(n-1) + f(n-2) for every n.

  • But this causes redundant work and is highly time consuming. The upper bound for time complexity would roughly be 2^n which is inefficient.

  • To solve the problem of redundant work, we can cache all the calculated results. That means, whenever we try to calculate the same subproblem after the first time, we can use a data structure to query the answer for stairs[i] in O(1) time.

  • This saves resources and brings down the time complexity to O(n).

๐Ÿ’ฌ Thought Process - Memoization

  • We will use the concepts of Dynamic Programming (Memoization/ Top down) to solve this problem.

  • For every n, we will calculate its answer using sub problems. Then we will cache this value using an array of size n+1.

  • If we come across any f(n) which was already solved, then we will return the cached value array[n].

๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ป Solution - Memoization

  • Below is the code for the approach for solving this problem using memoization.
class Solution {
    private int[] memo;
    public int climbStairs(int n) {
        memo = new int[n+1];
        if(n <= 2) return n;

        return climbStairsHelper(n);
    }

    private int climbStairsHelper(int n) {
        if(n < 0) return 0;
        if(n <= 2) return n;

        if(memo[n] != 0) return memo[n];

        return memo[n] = climbStairsHelper(n-1) + 
            climbStairsHelper(n-2);
    }
}
Time Complexity: O(n)
Space Complexity: O(n)

๐Ÿ’ฌ Thought Process - Tabulation

  • We can also solve this problem using DP bottom-up/ tabulation where we will solve for n from the smallest to the largest value.

  • We will declare an array of size n+1 and use the solved i-1 and i-1 cached values to solve for i.

๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ป Solution - Tabulation

  • Below is the code for the approach for solving this problem using tabulation.
class Solution {
    public int climbStairs(int n) {
        if(n <= 2) return n;
        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];
    }
}
Time Complexity: O(n)
Space Complexity: O(n)

๐Ÿ’ฌ Thought Process - Space optimisation

  • Since we only require the i-1 and i-2 values for every i, instead of caching all the i values in an array, we can use two separate variables to store the previous subproblem answers.

๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ป Solution - Space optimisation

  • Below is the code for the approach for solving this problem using space optimisation.
class Solution {
    public int climbStairs(int n) {
        if(n <= 2) return n;

        int first = 1;
        int second = 2;

        for(int i = 3; i <= n; i++) {
            int third = first + second;
            first = second;
            second = third;
        }
        return second;
    }
}
Time Complexity: O(n)
Space Complexity: O(1)


Conclusion

That's a wrap for today's problem. If you liked my explanation then please do drop a like/ comment. Also, please correct me if I've made any mistakes or if you want me to improve something!

Thank you for reading!