diff --git a/256. Paint House.py b/256. Paint House.py new file mode 100644 index 00000000..958bd1b1 --- /dev/null +++ b/256. Paint House.py @@ -0,0 +1,59 @@ +# EXHAUSTIVE SOLUTION + +# Time: O(2^n) n=> number of houses +# Space: O(n) As the recursion depth is only till the length of costs i.e the number of rows which determines the houses + +# Loop through the number of colors +# check in the helper function which color we use and use the remaining colors +# Check whats the cost of minimum between the two colors and add the current cost in it +class Solution: + def minCost(self, costs: List[List[int]]) -> int: + min_val = float('inf') + for n in range(len(costs[0])): + min_val = min(min_val, self.helper(costs, 0, n)) + return min_val + + def helper(self, costs, idx, n): + # base + if idx == len(costs): + return 0 + + # Logic + if n == 0: + choose_blue = self.helper(costs, idx + 1, n + 1) + choose_green = self.helper(costs, idx + 1, n + 2) + + return costs[idx][n] + min(choose_blue, choose_green) + elif n == 1: + choose_red = self.helper(costs, idx + 1, n - 1) + choose_green = self.helper(costs, idx + 1, n + 1) + + return costs[idx][n] + min(choose_red, choose_green) + else: + choose_red = self.helper(costs, idx + 1, n - 2) + choose_blue = self.helper(costs, idx + 1, n - 1) + + return costs[idx][n] + min(choose_red, choose_blue) + + + +# MEMOISATION SOLUTION +# Time: O(3n) => which is O(n) because we have 3 colors and n number of houses +# Space: O(3n) => which is O(n) we crate a matrix of n * number of colors + +# Just put everything in a memo matrix and use it to optimise on time + +class Solution: + def minCost(self, costs: List[List[int]]) -> int: + memo = [[-1 for _ in range(3)] for _ in range(len(costs))] + for m in range(len(costs) -1, -1, -1 ): + if m == len(costs) - 1: + memo[m][0] = costs[m][0] + memo[m][1] = costs[m][1] + memo[m][2] = costs[m][2] + else: + memo[m][0] = costs[m][0] + min(memo[m+1][1], memo[m+1][2]) + memo[m][1] = costs[m][1] + min(memo[m+1][0], memo[m+1][2]) + memo[m][2] = costs[m][2] + min(memo[m+1][0], memo[m+1][1]) + + return min(memo[0][0], memo[0][1],memo[0][2]) \ No newline at end of file diff --git a/518. Coin Change II.py b/518. Coin Change II.py new file mode 100644 index 00000000..8050c1d3 --- /dev/null +++ b/518. Coin Change II.py @@ -0,0 +1,70 @@ +# Time: O(2^m+n) => m is the amount and n is the no. of elements in coins array +# The time complexity is when we choose until amount is 1 and then we don't choose until the idx is not out of range +# Space: O(m+n) => That's the recursive space that will be used at the end + +# Everything is similar to coin change except returning choose + not_choose because we have to count all the possible paths +# Hence we have also changes the base cases accordingly so if amount is 0 it's valid and returns 1 and rest is invalid path which returns 0 +class Solution: + def change(self, amount: int, coins: List[int]) -> int: + return self.helper(coins, amount, 0) + def helper(self,coins,amount,idx): + # Base case + if amount == 0: + return 1 + if idx > (len(coins) - 1) or amount < 0: + return 0 + + # choose + choose = self.helper(coins,amount-coins[idx],idx) + # Not choose + not_choose = self.helper(coins,amount,idx+1) + + return choose + not_choose + +# MEMOIZATION SOLUTION +# Time and Space: O(m * n) where m is the len(coins) and n is the amount + +# Just add the values calculate (choose + not_choose) in a memo matrix and use the same amount for repeated sub problems +# Add the result in the memo matrix i.e the additioin of choose and not_choose +# return self.memo[idx][amount] from the function +class Solution: + def change(self, amount: int, coins: List[int]) -> int: + self.memo = [[-1 for _ in range(amount + 1)] for _ in range(len(coins) +1)] + + return self.helper(coins, amount, 0) + def helper(self,coins,amount,idx): + # Base case + if amount == 0: + return 1 + if idx > (len(coins) - 1) or amount < 0: + return 0 + if self.memo[idx][amount] != -1: + return self.memo[idx][amount] + + # choose + choose = self.helper(coins,amount-coins[idx],idx) + # Not choose + not_choose = self.helper(coins,amount,idx+1) + + self.memo[idx][amount] = choose + not_choose + return self.memo[idx][amount] + + +# TABULARISATION SOLUTION +# Time and Space: O(m * n) where m is the len(coins) and n is the amount +class Solution: + def change(self, amount: int, coins: List[int]) -> int: + rows = len(coins) + cols = amount + dp_matrix = [[0 for _ in range(cols + 1)] for _ in range(rows + 1)] + + for i in range(1,rows + 1): + for j in range(0,cols + 1): + if j == 0: + dp_matrix[i][j] = 1 + elif j < coins[i-1]: + dp_matrix[i][j] = dp_matrix[i - 1][j] + else: + dp_matrix[i][j] = dp_matrix[i - 1][j] + dp_matrix[i][j-coins[i - 1]] + + return dp_matrix[rows][cols]