Problem

There are a row of n houses, each house can be painted with one of the k colors. The cost of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent houses have the same color.

The cost of painting each house with a certain color is represented by a n x k cost matrix. For example, costs[0][0] is the cost of painting house 0 with color 0costs[1][2] is the cost of painting house 1 with color 2, and so on… Find the minimum cost to paint all houses.

Examples

Example 1

Input:
costs =[[14,2,11],[11,14,5],[14,3,10]]
Output: 10
Explanation:
The three house use color [1,2,1] for each house. The total cost is 10.

Example 2

Input:
costs =[[5]]
Output: 5
Explanation:
There is only one color and one house.

Challenge

Could you solve it in O(n*k).

Constraints

All costs are positive integers.

Solution

This problem is similar to Paint House 1 - N houses with 3 colors with no two adjacent houses with same color, but with k colors instead of 3.

Method 1 - Recursion

Code

Java
class Solution {

	public int minCostII(int[][] costs) {
		return minCostRecursive(costs, 0, -1);
	}

	private int helper(int[][] costs, int house, int lastColor) {
		if (house == costs.length) {
			return 0;
		}

		int min = Integer.MAX_VALUE;

		for (int color = 0; color < costs[0].length; color++) {
			if (color != lastColor) {
				int cost = costs[house][color] + helper(costs, house + 1, color);
				min = Math.min(min, cost);
			}
		}

		return min;
	}
}

Method 2 - Top Down DP

Code

Java
public class Solution {

	private Integer[][] memo;

	public int minCostII(int[][] costs) {
		memo = new Integer[costs.length][costs[0].length];
		return minCostRecursive(costs, 0, -1);
	}

	private int helper(int[][] costs, int house, int lastColor) {
		if (house == costs.length) {
			return 0;
		}

		if (lastColor != -1 && memo[house][lastColor] != null) {
			return memo[house][lastColor];
		}

		int min = Integer.MAX_VALUE;

		for (int color = 0; color < costs[0].length; color++) {
			if (color != lastColor) {
				int cost = costs[house][color] + helper(costs, house + 1, color);
				min = Math.min(min, cost);
			}
		}

		if (lastColor != -1) {
			memo[house][lastColor] = min;
		}

		return min;
	}
}

Method 3 - DP

This is a classic back pack problem.   - Define dp[n][k], where dp[i][j] means for house i with color j the minimum cost.   - Initial value: dp[0][j] = costs[0][j]. For others, dp[i][j] = Integer.MAX_VALUE;, i >= 1  - Transit function: dp[i][j] = Math.min(dp[i][j], dp[i-1][k] + cost[i][j]), where k != j.  - Final state: Min(dp[n-1][k]).

Code

Java
public int minCostII(int[][] costs) {
	if (costs == null || costs.length == 0) {
		return 0;
	}

	int n = costs.length;
	int k = costs[0].length;

	// dp[i][j] means the min cost painting for house i, with color j
	int[][] dp = new int[n][k];

	// Initialize the first row of the DP table with the costs of painting the first house with each color
	for (int color = 0; color < k; color++) {
		dp[0][color] = costs[0][color];
	}

	for (int house = 1; house < n; house++) {
		for (int color = 0; color < k; color++) {
			dp[house][color] = costs[house][color] + findMin(dp[house - 1], color);
		}
	}

	// Final state
	int minCost = Integer.MAX_VALUE;

	for (int i = 0; i < k; i++) {
		minCost = Math.min(minCost, dp[n - 1][i]);
	}

	return minCost;
}

Complexity

  • ⏰ Time complexity: O(n*k*k)
  • 🧺 Space complexity: O(n*k)

Method 4 - Space Optimized DP

Since dp[i][k] only depends on dp[i-1][j], we can use a 1-D DP solution.

Code

Java
public int minCostII(int[][] costs) {
	if (costs == null || costs.length == 0) {
		return 0;
	}
	 
	int n = costs.length;
	int k = costs[0].length;
	 
	// dp[j] means the min cost for color j
	int[] dp1 = new int[k];
	int[] dp2 = new int[k];
	 
	// Initialization
	for (int i = 0; i < k; i++) {
		dp1[i] = costs[0][i];
	}
	 
	for (int i = 1; i < n; i++) {
		for (int j = 0; j < k; j++) {
			dp2[j] = Integer.MAX_VALUE;
			for (int m = 0; m < k; m++) {
				if (m != j) {
					dp2[j] = Math.min(dp1[m] + costs[i][j], dp2[j]);
				}
			}
		}
		 
		for (int j = 0; j < k; j++) {
			dp1[j] = dp2[j];
		}
	}
	 
	// Final state
	int minCost = Integer.MAX_VALUE;
	for (int i = 0; i < k; i++) {
		minCost = Math.min(minCost, dp1[i]);
	}
	 
	return minCost;
}

Complexity

  • ⏰ Time complexity: O(n*k*k)
  • 🧺 Space complexity: O(k)