From 00dfe164b3f810c65132b341a3bf56293de079ee Mon Sep 17 00:00:00 2001 From: praxpk <23168694+praxpk@users.noreply.github.com> Date: Tue, 6 Jan 2026 15:16:36 -0500 Subject: [PATCH] DP-2 --- coin_change_2.py | 22 ++++++++++++++++ paint_houses.py | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 coin_change_2.py create mode 100644 paint_houses.py diff --git a/coin_change_2.py b/coin_change_2.py new file mode 100644 index 00000000..cba56674 --- /dev/null +++ b/coin_change_2.py @@ -0,0 +1,22 @@ +""" +time - o(n) +space - o(n) + +""" + +from typing import List + + +class Solution: + def change(self, amount: int, coins: List[int]) -> int: + dp = [[0] * (amount + 1) for _ in range(len(coins) + 1)] + for i in range(len(dp)): + dp[i][0] = 1 + for i in range(1, len(dp)): + for j in range(1, len(dp[0])): + coin = coins[i - 1] + dp[i][j] = dp[i - 1][j] + if coin <= j: + dp[i][j] += dp[i][j - coin] + + return dp[-1][-1] diff --git a/paint_houses.py b/paint_houses.py new file mode 100644 index 00000000..a1409242 --- /dev/null +++ b/paint_houses.py @@ -0,0 +1,65 @@ +""" +time - o(n) +space o(n) +we take a look at the problem as only one row of houses, in this case we just take the minimum. The same problem space is increased +by adding another row of houses, we then for the second row have to look at each paint cost and add the min paint cost from the previous row +without the current paint id. Finally, at the last row we just return the min. +""" + +from typing import List +import copy + + +class Solution: + def minCost(self, costs: List[List[int]]) -> int: + dp = copy.deepcopy(costs) + for i in range(1, len(costs)): + for j in range(len(costs[0])): + if j == 0: + dp[i][j] += min(dp[i - 1][1], dp[i - 1][2]) + if j == 1: + dp[i][j] += min(dp[i - 1][0], dp[i - 1][2]) + if j == 2: + dp[i][j] += min(dp[i - 1][0], dp[i - 1][1]) + return min(dp[-1]) + + +""" +recursive with memoization +time - o(n) without memo it is o(2^n) as we make a choice at every instance between two other paint costs but with memoization we only make + x number of calculations and store the result. Here x is 3 * 2 * n where 3 is the paint choices, 2 is the number of choices we make + at each node. +space o(n) + +we start at the top row and make all three paint choices and call the helper function, helper function goes down the rows recursively +and carries the previous choice and index along with cost and dict as parameters. Once the paint cost is calculated (min of the other two paint choices based on previous selection) +we store it based on previous selection and current index in the memo + +""" + + +class Solution2: + def minCost(self, costs: List[List[int]]) -> int: + if len(costs) == 1: + + return min(costs[0]) + memo = {} + cost = float("inf") + for i in range(len(costs[0])): + cost = min(cost, self.helper(costs, i, 1, costs[0][i], memo)) + return cost + + def helper(self, costs, prev_selection, index, curr_cost, memo): + if (prev_selection, index) in memo: + return memo[(prev_selection, index)] + if index == len(costs): + return curr_cost + next_cost = float("inf") + for i in range(len(costs[index])): + if i != prev_selection: + next_cost = min( + next_cost, self.helper(costs, i, index + 1, costs[index][i], memo) + ) + total_cost = next_cost + curr_cost + memo[(prev_selection, index)] = total_cost + return total_cost