[Cracking Coding Problems] Recursion and Dynamic Programming
Triple Step:
- A child is running up a staircase with n steps and can hop either 1 step, 2 steps, or 3 steps at a time. Implement a method to count how many possible ways the child can run up the stairs
Approach
Use
Top-Down
approach to store cache (Memoization)Base case
1 2 3
step[0] = 0 : stay at starting position step[1] = 1 step[2] = 2
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.Scanner;
public class CountWays {
public static int countWays(int n) {
long[] step = new long[n + 1];
step[0] = 1;
if (n >= 1) step[1] = 1;
if (n >= 2) step[2] = 2;
for (int i = 3; i <= n; i++) {
step[i] = step[i - 1] + step[i - 2] + step[i - 3];
}
return (int) step[n];
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter a number: ");
int n = scanner.nextInt();
System.out.println(countWays(n));
}
}
Scanner scanner = new Scanner(System.in)
Class in
java.util
packageRead the next integer value typed by user
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def countWays(n):
step = [0] * (n + 1)
step[0] = 1
if n >= 1:
step[1] = 1
if n >= 2:
step[2] = 2
for i in range(3, n + 1):
step[i] = step[i - 1] + step[i - 2] + step[i - 3]
return step[n]
if __name__ == "__main__":
n = int(input("Enter a number: "))
print(countWays(n))
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <vector>
using namespace std;
int countWays(int n) {
vector<long long> step(n+1, 0);
step[0] = 1;
if (n >= 1) step[1] = 1;
if (n >= 2) step[2] = 2;
for (int i = 3; i <= n; i++) {
step[i] = step[i-1] + step[i-2] + step[i-3];
}
return step[n];
}
int main() {
int n;
cin >> n;
cout << countWays(n) << endl;
return 0;
}
Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main
import (
"fmt"
)
func countWays(n int) int {
step := make([]int, n+1)
step[0] = 1
if n >= 1 {
step[1] = 1
}
if n >= 2 {
step[2] = 2
}
for i := 3; i <= n; i++ {
step[i] = step[i-1] + step[i-2] + step[i-3]
}
return step[n]
}
func main() {
var n int
fmt.Scan(&n)
fmt.Println(countWays(n))
}
Recursive algorithms can be very space inefficient. For the reason, it is often better to implement a recursive algorithm iteratively
If not use
Bottom-Up
andTop-Down
,Overall time complexity :
O(3^n)
Because there are up to 3 possible branches (hopping 1,2,3)
Space complexity is
O(n)
I solved all this problem with
Top-Down
ApproachOverall time complexity :
O(n)
Space complexity is
O(n)
However, I can ooptimize the space complexity using
Bottom-Up
ApproachOverall time complexity :
O(n)
Space complexity is
O(1)
Optimized Code (Bottom-Up)
- Implemented to
O(1)
by avoiding the use of a full array (vector<long long> step
)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
using namespace std;
int countWays(int n) {
if (n == 0) return 1;
if (n == 1) return 1;
if (n == 2) return 2;
long long prev3 = 1;
long long prev2 = 1;
long long prev1 = 2;
long long current = 0;
for (int i = 3; i <= n; i++) {
current = prev1 + prev2 + prev3;
prev3 = prev2;
prev2 = prev1;
prev1 = current;
}
return current;
}
int main() {
int n;
cin >> n;
cout << countWays(n) << endl;
return 0;
}
- Variables (prev1, prev2, prev2) are updated (shifted) to discard the oldest value and include the latest one
This post is licensed under CC BY 4.0 by the author.