Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions coin_change_two.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
class Solution:
"""
Time Complexity: O(m * n)
m = number of coins, n = amount
We fill an m x n DP table.

Space Complexity: O(m * n)
Using a 2D DP array dp[m+1][n+1].

Approaches:
1. Recursion + Memoization:
Try using or skipping each coin and recursively compute ways
to reach the remaining amount. Cache results to avoid recomputation.

2. Bottom-up DP (2D Tabulation):
Create a DP table where dp[i][j] represents the number of ways
to make amount j using the first i coins.
For each coin, we decide:
- Not using the coin (dp[i-1][j])
- Using the coin (dp[i][j - coin value])

3. Bottom-up DP (Optimized to 1D array):
Iterate coins first, then amount—which ensures combinations
(no permutation counting) and reduces space to O(n).
"""
def change(self, amount: int, coins: List[int]) -> int:
m = len(coins)
n = amount

# dp[i][j] = number of ways to form amount j using first i coins
dp = [[0] * (n + 1) for _ in range(m + 1)]

# Base case: One way to form amount 0 (choose nothing)
dp[0][0] = 1

for i in range(1, m + 1):
for j in range(n + 1):
# If current amount is less than the coin value,
# we cannot use this coin
if j < coins[i - 1]:
dp[i][j] = dp[i - 1][j]
else:
# Two choices:
# 1. Don't use the coin -> dp[i - 1][j]
# 2. Use the coin -> dp[i][j - coin_value]
dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i - 1]]

return dp[m][n]
45 changes: 45 additions & 0 deletions paint_house.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class Solution:
"""
Time Complexity: O(n) -> We process each house once.
Space Complexity: O(1) -> We only store costs for 3 colors per step.

Approaches:
1. Top-down DP (Recursion + Memoization):
Recursively explore all ways to paint each house while ensuring no two adjacent
houses share the same color. Cache results of subproblems to avoid recomputation.

2. Bottom-up DP (Tabulation with DP Table):
Build a dp[n][3] table where each row stores the minimum cost to paint up to
that house with each color. Each entry depends on the minimum of the other two
colors from the previous house.

3. Bottom-up DP with Space Optimization (Tabulation -> O(1) Space):
Instead of a full dp table, keep only the previous house's three minimum costs.
Update these values iteratively to compute the final minimum cost.
"""
def minCost(self, costs: List[List[int]]) -> int:
n = len(costs)

# If there are no houses, total cost is 0
if n == 0:
return 0

# Initialize minimum costs for painting the first house
chooseRedPrev = costs[0][0]
chooseBluePrev = costs[0][1]
chooseGreenPrev = costs[0][2]

# Iterate through each subsequent house
for i in range(1, n):
# Compute the new costs if we paint this house each color
chooseRed = costs[i][0] + min(chooseBluePrev, chooseGreenPrev)
chooseBlue = costs[i][1] + min(chooseRedPrev, chooseGreenPrev)
chooseGreen = costs[i][2] + min(chooseRedPrev, chooseBluePrev)

# Update previous values for the next iteration
chooseRedPrev, chooseBluePrev, chooseGreenPrev = (
chooseRed, chooseBlue, chooseGreen
)

# The answer is the minimum of the last computed color choices
return min(chooseRedPrev, chooseBluePrev, chooseGreenPrev)