Skip to content

Commit 61da6c2

Browse files
feat: add NeetCode 150 - 1D Dynamic Programming category (8 problems)
Complete implementations with multiple approaches: - Climbing Stairs (Fibonacci pattern) - House Robber I & II (Circular constraint) - Longest Palindromic Substring (Expand around centers) - Decode Ways (String decoding) - Coin Change (Minimum coins) - Word Break (String segmentation) - Combination Sum IV (Order matters) All solutions include DP, space-optimized DP, and alternative approaches
1 parent 74f181c commit 61da6c2

File tree

16 files changed

+2029
-0
lines changed

16 files changed

+2029
-0
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Climbing Stairs
2+
3+
## Problem Statement
4+
5+
You are climbing a staircase. It takes `n` steps to reach the top.
6+
7+
Each time you can either climb `1` or `2` steps. In how many distinct ways can you climb to the top?
8+
9+
## Examples
10+
11+
**Example 1:**
12+
```
13+
Input: n = 2
14+
Output: 2
15+
Explanation: There are two ways to climb to the top.
16+
1. 1 step + 1 step
17+
2. 2 steps
18+
```
19+
20+
## Approach
21+
22+
### Method 1: Dynamic Programming (Recommended)
23+
1. Use DP to store number of ways to reach each step
24+
2. dp[i] = dp[i-1] + dp[i-2]
25+
3. Similar to Fibonacci sequence
26+
4. Most efficient approach
27+
28+
**Time Complexity:** O(n) - Single pass
29+
**Space Complexity:** O(n) - DP array
30+
31+
### Method 2: Space-Optimized DP
32+
1. Use only two variables instead of array
33+
2. Update variables iteratively
34+
3. Most memory efficient
35+
36+
**Time Complexity:** O(n) - Single pass
37+
**Space Complexity:** O(1) - Two variables
38+
39+
## Algorithm
40+
41+
```
42+
1. Initialize dp[0] = 1, dp[1] = 1
43+
2. For i from 2 to n:
44+
dp[i] = dp[i-1] + dp[i-2]
45+
3. Return dp[n]
46+
```
47+
48+
## Key Insights
49+
50+
- **Fibonacci Pattern**: Same as Fibonacci sequence
51+
- **State Transition**: dp[i] = dp[i-1] + dp[i-2]
52+
- **Base Cases**: dp[0] = 1, dp[1] = 1
53+
- **Space Optimization**: Use only two variables
54+
55+
## Alternative Approaches
56+
57+
1. **Recursion**: Use recursive approach with memoization
58+
2. **Matrix Exponentiation**: Use matrix power for O(log n)
59+
3. **Mathematical Formula**: Use Binet's formula
60+
61+
## Edge Cases
62+
63+
- n = 0: Return 1
64+
- n = 1: Return 1
65+
- n = 2: Return 2
66+
- Large n: Handle overflow
67+
68+
## Applications
69+
70+
- Fibonacci sequence
71+
- Dynamic programming patterns
72+
- Algorithm design patterns
73+
- Interview preparation
74+
- System design
75+
76+
## Optimization Opportunities
77+
78+
- **Space Optimization**: O(1) space complexity
79+
- **Single Pass**: O(n) time complexity
80+
- **No Recursion**: Avoid stack overflow
81+
- **Memory Efficient**: Use only two variables
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/**
2+
* Time Complexity: O(n) - Single pass
3+
* Space Complexity: O(n) - DP array
4+
*/
5+
class Solution {
6+
public int climbStairs(int n) {
7+
if (n <= 1) {
8+
return 1;
9+
}
10+
11+
int[] dp = new int[n + 1];
12+
dp[0] = 1;
13+
dp[1] = 1;
14+
15+
for (int i = 2; i <= n; i++) {
16+
dp[i] = dp[i - 1] + dp[i - 2];
17+
}
18+
19+
return dp[n];
20+
}
21+
}
22+
23+
// Alternative approach using space-optimized DP
24+
class SolutionSpaceOptimized {
25+
public int climbStairs(int n) {
26+
if (n <= 1) {
27+
return 1;
28+
}
29+
30+
int prev2 = 1; // dp[i-2]
31+
int prev1 = 1; // dp[i-1]
32+
33+
for (int i = 2; i <= n; i++) {
34+
int current = prev1 + prev2;
35+
prev2 = prev1;
36+
prev1 = current;
37+
}
38+
39+
return prev1;
40+
}
41+
}
42+
43+
// Alternative approach using recursion with memoization
44+
class SolutionMemoization {
45+
public int climbStairs(int n) {
46+
int[] memo = new int[n + 1];
47+
Arrays.fill(memo, -1);
48+
return climbStairsHelper(n, memo);
49+
}
50+
51+
private int climbStairsHelper(int n, int[] memo) {
52+
if (n <= 1) {
53+
return 1;
54+
}
55+
56+
if (memo[n] != -1) {
57+
return memo[n];
58+
}
59+
60+
memo[n] = climbStairsHelper(n - 1, memo) + climbStairsHelper(n - 2, memo);
61+
return memo[n];
62+
}
63+
}
64+
65+
// Alternative approach using matrix exponentiation
66+
class SolutionMatrix {
67+
public int climbStairs(int n) {
68+
if (n <= 1) {
69+
return 1;
70+
}
71+
72+
int[][] matrix = {{1, 1}, {1, 0}};
73+
int[][] result = matrixPower(matrix, n);
74+
75+
return result[0][0];
76+
}
77+
78+
private int[][] matrixPower(int[][] matrix, int n) {
79+
if (n == 1) {
80+
return matrix;
81+
}
82+
83+
if (n % 2 == 0) {
84+
int[][] half = matrixPower(matrix, n / 2);
85+
return matrixMultiply(half, half);
86+
} else {
87+
int[][] half = matrixPower(matrix, n / 2);
88+
return matrixMultiply(matrixMultiply(half, half), matrix);
89+
}
90+
}
91+
92+
private int[][] matrixMultiply(int[][] a, int[][] b) {
93+
int[][] result = new int[2][2];
94+
result[0][0] = a[0][0] * b[0][0] + a[0][1] * b[1][0];
95+
result[0][1] = a[0][0] * b[0][1] + a[0][1] * b[1][1];
96+
result[1][0] = a[1][0] * b[0][0] + a[1][1] * b[1][0];
97+
result[1][1] = a[1][0] * b[0][1] + a[1][1] * b[1][1];
98+
return result;
99+
}
100+
}
101+
102+
// Alternative approach using mathematical formula
103+
class SolutionMathematical {
104+
public int climbStairs(int n) {
105+
double sqrt5 = Math.sqrt(5);
106+
double phi = (1 + sqrt5) / 2;
107+
double psi = (1 - sqrt5) / 2;
108+
109+
return (int) Math.round((Math.pow(phi, n + 1) - Math.pow(psi, n + 1)) / sqrt5);
110+
}
111+
}
112+
113+
// Alternative approach using iterative with variables
114+
class SolutionIterative {
115+
public int climbStairs(int n) {
116+
if (n <= 1) {
117+
return 1;
118+
}
119+
120+
int a = 1, b = 1, c;
121+
122+
for (int i = 2; i <= n; i++) {
123+
c = a + b;
124+
a = b;
125+
b = c;
126+
}
127+
128+
return b;
129+
}
130+
}
131+
132+
// More concise version
133+
class SolutionConcise {
134+
public int climbStairs(int n) {
135+
if (n <= 1) return 1;
136+
137+
int prev2 = 1, prev1 = 1;
138+
for (int i = 2; i <= n; i++) {
139+
int curr = prev1 + prev2;
140+
prev2 = prev1;
141+
prev1 = curr;
142+
}
143+
return prev1;
144+
}
145+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Coin Change
2+
3+
## Problem Statement
4+
5+
You are given an integer array `coins` representing coins of different denominations and an integer `amount` representing a total amount of money.
6+
7+
Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return `-1`.
8+
9+
You may assume that you have an infinite number of each kind of coin.
10+
11+
## Examples
12+
13+
**Example 1:**
14+
```
15+
Input: coins = [1,3,4], amount = 6
16+
Output: 2
17+
Explanation: 6 = 3 + 3
18+
```
19+
20+
## Approach
21+
22+
### Method 1: Dynamic Programming (Recommended)
23+
1. Use DP to store minimum coins for each amount
24+
2. dp[i] = min(dp[i], dp[i-coin] + 1) for each coin
25+
3. Initialize dp[0] = 0, others = infinity
26+
4. Most efficient approach
27+
28+
**Time Complexity:** O(amount * coins.length)
29+
**Space Complexity:** O(amount) - DP array
30+
31+
### Method 2: BFS
32+
1. Use BFS to find minimum steps
33+
2. Each level represents one coin
34+
3. Less efficient than DP
35+
36+
**Time Complexity:** O(amount * coins.length)
37+
**Space Complexity:** O(amount) - Queue
38+
39+
## Algorithm
40+
41+
```
42+
1. Initialize dp[0] = 0, dp[i] = infinity for i > 0
43+
2. For each amount from 1 to amount:
44+
a. For each coin:
45+
b. If coin <= amount: dp[amount] = min(dp[amount], dp[amount-coin] + 1)
46+
3. Return dp[amount] or -1 if infinity
47+
```
48+
49+
## Key Insights
50+
51+
- **State Transition**: dp[i] = min(dp[i], dp[i-coin] + 1)
52+
- **Infinite Coins**: Can use same coin multiple times
53+
- **Minimum Coins**: Find minimum number of coins
54+
- **Impossible Case**: Return -1 if amount cannot be made
55+
56+
## Alternative Approaches
57+
58+
1. **BFS**: Use BFS for minimum steps
59+
2. **Recursion**: Use recursive approach with memoization
60+
3. **Greedy**: Not always optimal
61+
62+
## Edge Cases
63+
64+
- Empty coins: Return -1
65+
- Amount = 0: Return 0
66+
- No solution: Return -1
67+
- Single coin: Handle appropriately
68+
69+
## Applications
70+
71+
- Dynamic programming patterns
72+
- Optimization problems
73+
- Algorithm design patterns
74+
- Interview preparation
75+
- System design
76+
77+
## Optimization Opportunities
78+
79+
- **Dynamic Programming**: Most efficient approach
80+
- **Single Pass**: O(amount * coins) time complexity
81+
- **Space Efficient**: O(amount) space complexity
82+
- **No Recursion**: Avoid stack overflow

0 commit comments

Comments
 (0)