Hello! Welcome back to our study of Dynamic Programming.
In our last lesson, we focused on the mechanics of converting a top-down, memoized solution into a bottom-up, tabulated one, and then optimizing for space. Today, we put that theory into practice. Our goal is to solve two of the most fundamental 1D DP problems you will encounter in technical interviews: Climbing Stairs and House Robber.
By mastering these, you will solidify a powerful and repeatable pattern for tackling a wide range of problems involving sequences. This lesson is all about moving from understanding the "how" to building the "what" from scratch, a crucial step in your interview preparation.
The 1D DP Problem-Solving Pattern
As a quick recap, our general strategy for these problems will be:
- Understand the Problem & Choices: Break down the problem. At any given point (e.g., at step
ior housei), what are the possible decisions? - Define the State & Recurrence Relation: Define what
dp[i]will represent. Usually, it's the answer to the subproblem for the firstielements. Then, formulate the recurrence relation that connectsdp[i]to previous states (e.g.,dp[i-1],dp[i-2]). - Identify Base Cases: Determine the solutions for the smallest subproblems (e.g.,
dp[0],dp[1]) that don't depend on any others. - Implement Bottom-Up (Tabulation): Write a loop that builds your
dptable from the base cases up to the final answer. - Optimize for Space: Check if the recurrence for
dp[i]only depends on a fixed number of previous states. If so, replace thedparray with a few variables to reduce space complexity, typically fromO(n)toO(1).
Let's apply this pattern.
Problem 1: Climbing Stairs (LeetCode 70)
This problem is a classic introduction to DP and is functionally identical to the Fibonacci sequence we've discussed.
The 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?
Let's break this down using our pattern.
Step 1: Understanding the Choices
To reach the n-th step, what was your last move? You must have come from either:
- Step
n-1(by taking a single 1-step). - Step
n-2(by taking a single 2-step).
There are no other ways to arrive at exactly step n.
Step 2: State and Recurrence Relation
- State: Let
dp[i]be the number of distinct ways to reach stepi. - Recurrence: The total ways to reach step
iis the sum of the ways to reach the steps from which you can jump toi. Therefore:
This is the Fibonacci recurrence relation. The logic is that every path to i-1 can be extended to i with a 1-step, and every path to i-2 can be extended to i with a 2-step.

The following video provides an excellent walkthrough, from the initial brute-force recursive thinking to the final optimized DP solution.
Climbing Stairs - Dynamic Programming - Leetcode 70 - Python
Watch this video from NeetCode to see a complete breakdown of the Climbing Stairs problem. It visualizes the brute-force decision tree, identifies the overlapping subproblems, and builds up to the optimized O(1) space solution.
Watch the video from 00:47 to the end (around 17:58). Pay close attention to these key stages: 00:47 - 08:05: How the problem is visualized as a decision tree and how this reveals redundant computations (overlapping subproblems). 08:05 - 11:08: The concept of memoization to cache results. 11:08 - 15:16: The transition to a bottom-up DP approach, filling an array from the base cases. 15:16 - 17:58: The final space optimization to achieve an O(1) space solution.
Steps 3-5: Implementation and Optimization
As shown in the video and our previous lesson, we can now implement the solution.
-
Tabulation (O(n) space):
- State:
dparray of sizen+1. - Base Cases:
dp[0] = 1(one way to be at the start),dp[1] = 1(one way to climb one step). - Loop:
for i from 2 to n, applydp[i] = dp[i-1] + dp[i-2]. - Result:
dp[n].
- State:
-
Space-Optimized (O(1) space):
- Since we only need the last two values, we can use two variables. Let's call them
one_step_backandtwo_steps_back. - Initialize
one_step_back = 1,two_steps_back = 1. - Loop
n-1times, and in each iteration, calculatecurrent = one_step_back + two_steps_back, then updatetwo_steps_back = one_step_backandone_step_back = current.
- Since we only need the last two values, we can use two variables. Let's call them
The following reading provides a concise summary of the intuition, solution approach, and a clean Python implementation.
70. Climbing Stairs - In-Depth Explanation
For a quick textual reference, the 'Climbing Stairs - In-Depth Explanation' on AlgoMonster provides a clear summary of the logic and implementation.
Read the sections 'Intuition', 'Solution Approach', and 'Solution Implementation'. This reinforces the Fibonacci pattern and the space-optimized iterative solution.
Problem 2: House Robber (LeetCode 198)
Now let's apply the same pattern to a slightly different problem. This problem is another interview favorite.
The Problem: You are a professional robber planning to rob houses along a street. Each house has a certain amount of money. The only constraint is that you cannot rob adjacent houses. Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob.
Step 1: Understanding the Choices
When you are at house i, you have two choices:
- Rob house
i: If you do, you cannot rob housei-1. The maximum money you could have up to this point would benums[i]plus the maximum you could have robbed up to housei-2. - Do NOT rob house
i: If you skip housei, the maximum money you can have is simply the maximum you could have robbed up to housei-1.
Step 2: State and Recurrence Relation
- State: Let
dp[i]be the maximum amount of money you can rob from the firstihouses (i.e., from index0toi-1of thenumsarray). - Recurrence: Based on the choices above, the maximum money you can get at house
iis themaxof the two scenarios:
dp[i-1]corresponds to not robbing housei(indexi-1).dp[i-2] + nums[i-1]corresponds to robbing housei.
This video from NeetCode explains the problem with the same clear, step-by-step reasoning.
House Robber - Leetcode 198 - Python Dynamic Programming
This video on the House Robber problem will walk you through deriving the recurrence relation and implementing the optimized DP solution.
Watch the video from the beginning to 10:34. Focus on: 00:00 - 02:45: Understanding the problem constraints and why a brute-force approach is inefficient. 02:45 - 05:06: How to break the problem into subproblems and derive the crucial recurrence relation. 05:06 - 10:34: The bottom-up DP logic and the final O(1) space optimization using just two variables.
Steps 3-5: Implementation and Optimization
-
Tabulation (O(n) space):
- State:
dparray of sizen+1. - Base Cases:
dp[0] = 0(no houses, no money),dp[1] = nums[0](one house, rob it). - Loop:
for i from 2 to n, applydp[i] = max(dp[i-1], dp[i-2] + nums[i-1]). - Result:
dp[n].
- State:
-
Space-Optimized (O(1) space):
- Similar to Climbing Stairs,
dp[i]only depends ondp[i-1]anddp[i-2]. We can use two variables. Let's call themrob1(max money up toi-2) androb2(max money up toi-1). - Initialize
rob1 = 0,rob2 = 0. - Loop through each number
ninnums:- Calculate
new_rob = max(rob2, rob1 + n). This is our recurrence. - Update
rob1 = rob2. - Update
rob2 = new_rob.
- Calculate
- The final answer is
rob2.
- Similar to Climbing Stairs,
For another perspective, this article breaks down the problem using a structured framework.
Solving The House Robber LeetCode Problem
The article 'Solving The House Robber LeetCode Problem' uses a systematic method to break down the problem, which is very useful for developing a repeatable strategy in interviews.
Read from 'Step 1: Identify a dynamic programming problem' to 'Step 4: Adopt an implementation approach'. This will reinforce how to recognize DP properties and formulate the recurrence relation, which are the most critical thinking steps.
Test your understanding!
You are given an integer array cost, where cost[i] is the cost of the i-th step on a staircase. Once you pay the cost, you can either climb one or two steps. You can start from either step 0 or step 1.
Return the minimum cost to reach the top of the floor. (The "top" is one step past the last index).
This is the "Min Cost Climbing Stairs" problem (LeetCode 746). Try to formulate the DP solution.
Hint: Think about the cost to arrive at step i. Where could you have come from?
Show answer
Let dp[i] be the minimum cost to reach step i.
Recurrence Relation:
To reach step i, you must have come from either step i-1 or step i-2.
- If you came from
i-1, the cost isdp[i-1] + cost[i-1]. - If you came from
i-2, the cost isdp[i-2] + cost[i-2].
So, the minimum cost to reach step i is:dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
Base Cases:
Since you can start at step 0 or 1 for free, the cost to reach them is 0.dp[0] = 0dp[1] = 0
Implementation (O(1) space):
We can use two variables, cost1 and cost2, to track the min cost to reach the previous two steps.
def minCostClimbingStairs(cost):
# cost1 = min cost to reach step i-2
# cost2 = min cost to reach step i-1
cost1, cost2 = 0, 0
for c in cost:
# dp[i] = c + min(dp[i-1], dp[i-2])
# Note: the cost 'c' is the cost of the *current* step, which is different from the problem statement's indexing.
# A clearer way:
# Let cost1 be the min cost to reach the previous step
# Let cost2 be the min cost to reach two steps ago
# current_cost is the cost to reach the *next* step from either i-1 or i-2
current_cost = c + min(cost1, cost2)
cost2 = cost1
cost1 = current_cost
# The final answer is the min cost to reach one step past the end
# which is min(cost1, cost2)
return min(cost1, cost2)
# A more direct implementation using the problem's indexing
def minCostClimbingStairs_v2(cost):
n = len(cost)
dp = [0] * (n + 1) # dp[i] is min cost to reach step i
for i in range(2, n + 1):
dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
return dp[n]
The key is realizing the cost is paid to leave a step. Both problems demonstrate the same underlying DP pattern.
Conclusion
Today, we solidified the 1D Dynamic Programming pattern by applying it to two essential interview problems. You have practiced the complete workflow: from understanding the problem's choices to deriving a recurrence, and from implementing a simple tabulated solution to optimizing it for space.
Key Takeaways:
- 1D DP Pattern: Most 1D DP problems can be solved by defining a state
dp[i]that represents the solution for the prefix of sizei, and then finding a recurrence that relatesdp[i]todp[i-1]anddp[i-2]. - Climbing Stairs: This is a variation of the Fibonacci sequence. The number of ways to reach a state is the sum of ways to reach previous states.
dp[i] = dp[i-1] + dp[i-2]. - House Robber: This is a "choice" problem. The optimal solution at a state is the
maxorminof choices made at that state.dp[i] = max(dp[i-1], dp[i-2] + value[i]). - Space Optimization: Always be on the lookout to optimize space. If your recurrence only depends on a constant number of previous states, you can almost certainly get to an
O(1)space solution.
In our next lesson, we will extend these ideas to a new dimension. We'll tackle 2D Dynamic Programming, where the state dp[i][j] depends on two variables. This is common in problems involving grids, matrices, or two strings, like the famous "Longest Common Subsequence" problem. The core skills of defining state and finding a recurrence will remain just as critical.