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
127 changes: 127 additions & 0 deletions coin-change-2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@

// Solution -1

// TimeComplexity: O(n × amount)
// SpaceComplexity: O(amount)
//Explanation: I use a 1D array arr where arr[j] represents the number of ways to make amount j.
// I initialize arr[0] = 1 because there is one way to make amount 0 (choose nothing). For each coin, I iterate through amounts and update
class Solution {
public int change(int amount, int[] coins) {
int[] arr = new int[amount+1];
for (int j=0; j<amount+1; j++) {
if(j==0){
arr[j] =1;
} else{
arr[j] =0;
}
}

for(int i=0; i<coins.length; i++){
for(int j=0; j<amount+1; j++){
if(j>=coins[i]) {
arr[j] = arr[j] + arr[j-coins[i]];
}

}
}
return arr[amount];
}
}


// Solution - 2

// TimeComplexity: O(n × amount)
// SpaceComplexity: O(n × amount)
// Explanation: Here dp[i][j] represents the number of ways to make amount j using the first i coins. For each coin, I either: Don’t choose it → dp[i-1][j]; Choose it → dp[i][j - coin]
// I add both cases to get total combinations.


class Solution {
public int change(int amount, int[] coins) {
int[][] dp = new int[coins.length+1][amount+1];
for(int i=1; i<coins.length+1; i++) {
for (int j=0; j<amount+1; j++){
if(j==0) {
dp[i][j] =1;
} else if(j<coins[i-1]) {
dp[i][j] = dp[i-1][j];
} else {
dp[i][j] = dp[i-1][j] + dp[i][j-coins[i-1]];
}
}
}
return dp[coins.length][amount];
}
}


// Solution - 3

// TimeComplexity: O(n × amount)
// SpaceComplexity: O(n × amount)
// Explanation: I use recursion where at each step I either: Skip the current coin (move to next index)
// Take the current coin (reduce amount but stay at same index). I store results in dp[idx][amount] to avoid recomputation. Each state is solved once

class Solution {
public int change(int amount, int[] coins) {
Integer[][] dp = new Integer[coins.length+1][amount+1];
return helper(amount, coins, 0, dp);
}

private int helper(int amount, int[] coins, int idx, Integer[][] dp){

// base
if(amount<0|| idx>=coins.length) return 0;
if(amount ==0) {
return 1;
}

if(dp[idx][amount] !=null) {
return dp[idx][amount];
}


// no choose
int case1= helper(amount, coins, idx+1,dp);

// choose
int case2= helper(amount-coins[idx], coins, idx, dp);
int sum = case1+case2;
dp[idx][amount] = sum;

return sum;
}
}


// Solution - 4


// Time Complexity: O(2^n+m) where m is amount and n is length of coins array
// Space Complexity: O(m+n)
// Explanation: Here I recursively try both choices (take or skip coin) without memoization.
// This causes repeated recomputation of the same states, leading to exponential time complexity.

class Solution {
public int change(int amount, int[] coins) {
return helper(amount, coins, 0);

}

private int helper(int amount, int[] coins, int idx){
// base
if(amount<0|| idx>=coins.length) return 0;
if(amount ==0) {
return 1;
}

// no choose
int case1= helper(amount, coins, idx+1);

// choose
int case2= helper(amount-coins[idx], coins, idx);

return case1+case2;
}
}
144 changes: 144 additions & 0 deletions paint-house.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Solution - 1

// TimeComplexity: O(n)
// SpaceComplexity: O(1)
// Explanation: I solve it from the last house to the first. The array dp[0], dp[1], dp[2] represents the minimum cost to paint from the next house onward
// if the current house is painted Red, Blue, or Green. For each house, I add its painting cost plus the minimum of the other two colors from the next house (since adjacent houses cannot have the same color).
// Finally, I return the minimum of the three values.

class Solution {
public int minCost(int[][] costs) {
if(costs.length ==1) {
return Math.min(costs[0][0], Math.min(costs[0][1], costs[0][2]));
}
Integer[] dp = new Integer[3];
dp[0] = costs[costs.length-1][0];
dp[1] = costs[costs.length-1][1];
dp[2] = costs[costs.length-1][2];
for(int i =costs.length-2; i>-1; i--) {
int prev0 = dp[0];
int prev1 = dp[1];
int prev2 = dp[2];

dp[0] = costs[i][0] + Math.min(prev1, prev2);
dp[1] = costs[i][1] + Math.min(prev0, prev2);
dp[2] = costs[i][2] + Math.min(prev0, prev1);
}
return Math.min(dp[0], Math.min(dp[1], dp[2]));
}
}


// Solution - 2

// TimeComplexity: O(n)
// SpaceComplexity: O(n)
// Explanation: Here I use a dp[i][color] table where it stores the minimum cost to paint from house i to the end if house i is painted with color.
// I fill the table from bottom to top using the same transition rule (choose the minimum of the other two colors from the next house).
// The answer is the minimum among the three colors for house 0.

class Solution {
public int minCost(int[][] costs) {
if(costs.length ==1) {
return Math.min(costs[0][0], Math.min(costs[0][1], costs[0][2]));
}
Integer[][] dp = new Integer[costs.length][3];
dp[costs.length-1][0] = costs[costs.length-1][0];
dp[costs.length-1][1] = costs[costs.length-1][1];
dp[costs.length-1][2] = costs[costs.length-1][2];
for(int i =costs.length-2; i>-1; i--) {
dp[i][0] = costs[i][0] + Math.min(dp[i+1][1], dp[i+1][2]);
dp[i][1] = costs[i][1] + Math.min(dp[i+1][0], dp[i+1][2]);
dp[i][2] = costs[i][2] + Math.min(dp[i+1][0], dp[i+1][1]);
}
return Math.min(dp[0][0], Math.min(dp[0][1], dp[0][2]));
}
}

// Solution - 3

// TimeComplexity: O(n)
// SpaceComplexity: O(n)
// Explanation: I use recursion and at each house decide the next house’s color (cannot be the same).
// The function returns the minimum cost starting from index idx with a given color. I store results in dp[idx][color] to avoid recomputation.
// This ensures each state is solved once.

class Solution {
public int minCost(int[][] costs) {
Integer[][] dp = new Integer[costs.length][3];
// Red case
int case1= helper(costs, 0, 0, dp);
// blue case
int case2= helper(costs, 1, 0, dp);
// green case
int case3= helper(costs, 2, 0, dp);
return Math.min(case1, Math.min(case2, case3));
}

private int helper(int[][] costs, int color, int idx, Integer[][] dp) {
// base
if(idx==costs.length) return 0;
if(dp[idx][color]!=null) return dp[idx][color];

// logic
int case1;
int case2;
if(color==0) {
case1 = costs[idx][color] + helper(costs, 1, idx+1, dp);
case2 = costs[idx][color] + helper(costs, 2, idx+1, dp);

} else if(color==1) {
case1 = costs[idx][color] + helper(costs, 0, idx+1, dp);
case2 = costs[idx][color] + helper(costs, 2, idx+1, dp);
} else {
case1 = costs[idx][color] + helper(costs, 0, idx+1, dp);
case2 = costs[idx][color] + helper(costs, 1, idx+1, dp);
}
int min = Math.min(case1, case2);
dp[idx][color] = min;
return min;
}
}



// Solution - 4

// TimeComplexity: O(2ⁿ)
// SpaceComplexity: O(n)
// Explanation: Here I recursively try both possible colors for the next house at every step without storing results.
// This causes repeated calculations of the same states, leading to exponential time complexity.


class Solution {
public int minCost(int[][] costs) {
// Red case
int case1= helper(costs, 0, 0);
// blue case
int case2= helper(costs, 1, 0);
// green case
int case3= helper(costs, 2, 0);
return Math.min(case1, Math.min(case2, case3));
}

private int helper(int[][] costs, int color, int idx) {
// base
if(idx==costs.length) return 0;

// logic
int case1;
int case2;
if(color==0) {
case1 = costs[idx][color] + helper(costs, 1, idx+1);
case2 = costs[idx][color] + helper(costs, 2, idx+1);

} else if(color==1) {
case1 = costs[idx][color] + helper(costs, 0, idx+1);
case2 = costs[idx][color] + helper(costs, 2, idx+1);
} else {
case1 = costs[idx][color] + helper(costs, 0, idx+1);
case2 = costs[idx][color] + helper(costs, 1, idx+1);
}
return Math.min(case1, case2);
}
}