Distinct way to reach top of Stairs | Climbing Stairs Top-Down Approach

Question:

Problem :
You are climbing a staircase. It takes n steps to reach the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

Input: n = 3

Output: 3

Explanation: There are three ways to climb to the top.

  1. 1 step + 1 step + 1 step
  2. 1 step + 2 steps
  3. 2 steps + 1 step

Here is my 2 different approach for this Problem.

Approach 1:

Class Solution: 
    def climbStairs(self, n):
        dic = {1:1, 2:2}
        if n not in dic:
            dic[n] = self.climbStairs(n-1) + self.climbStairs(n-2)
        return dic[n]

Approach 2:

Class Solution:
    def __init__(self):
        self.dic = {1:1, 2:2}
    
    def climbStairs(self, n):
        if n not in self.dic:
            self.dic[n] = self.climbStairs(n-1) + self.climbStairs(n-2)
        return self.dic[n]

Now the problem is whenever n goes beyond 36 I get time limit exceeded from Approach 1 but Approach 2 works perfectly fine.

I’m solving this problem on leetcode. Even I tried to run this on VS code but execution is very very slow from n > 40.

I’m not understanding what impact does dictionary inside constructor makes in making execution faster.

Asked By: Anupam Chowkshey

||

Answers:

Approach 2 passes because it uses a technique called memoization. In the first approach, if you carefully check which functions calls are made, you quickly figure out that there are overlapping problems and it leads to O(2^n) solution, while with memoization it’s only O(n).


In the first approach you rewrite dict on every function call, probably this is not what you want. You can move it to the class level, like so:

class Solution:
    dic = {1: 1, 2: 2}

    def climbStairs(self, n):
        if n not in self.dic:
            self.dic[n] = self.climbStairs(n - 1) + self.climbStairs(n - 2)
        return self.dic[n]
Answered By: funnydman

The first line in approach 1 creates a new dictionary {1: 1, 2: 2} with each call. If you wanted to use a shared dictionary, you would have to pass it as an argument to the function or have it as an instance variable like you do in approach 2.

This is how you can share the dictionary and pass it every time as an argument:

class Solution: 
    def climbStairs(self, n, dic = {1: 1, 2: 2}):
        if n not in dic:
            dic[n] = self.climbStairs(n-1, dic) + self.climbStairs(n-2, dic)
        return dic[n]

Note that the default value {1: 1, 2: 2} for dic is there just so that you can call climbstairs(36) and don’t have to do it like climbstairs(36, {1: 1, 2: 2}). The default value doesn’t get used any other time than the first call.

Answered By: Filip Müller
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.