Problem Statement (Asked By Facebook)
A builder plans to construct N houses in a row, where each house can be painted in K different colors. The goal is to minimize the total painting cost, ensuring that no two adjacent houses have the same color.
You are given an N × K matrix, where:
n
), andk
).matrix[n][k]
indicates the cost to paint house n
with color k
.Return the minimum total cost to paint all N
houses while satisfying the constraint that no two consecutive houses have the same color.
Problem link: https://leetcode.com/problems/paint-house-iii/description/
Disclaimer: Try solving the problem on your own first! Use this solution only as a reference to learn and improve.
public class PaintHousesBruteForce { public static int minCostToPaint(int[][] costs) { if (costs == null || costs.length == 0) return 0; return helper(costs, 0, -1); } private static int helper(int[][] costs, int house, int prevColor) { if (house == costs.length) return 0; // All houses painted int minCost = Integer.MAX_VALUE; for (int color = 0; color < costs[0].length; color++) { if (color != prevColor) { // Ensure adjacent houses have different colors int currentCost = costs[house][color] + helper(costs, house + 1, color); minCost = Math.min(minCost, currentCost); } } return minCost; } public static void main(String[] args) { int[][] costs = { {1, 3, 5}, {2, 9, 4}, {8, 3, 6}, {4, 7, 2} }; System.out.println(minCostToPaint(costs)); // Output: 8 (but inefficient) } }
dp[i]
) public class PaintHousesDP { public static int minCostToPaint(int[][] costs) { if (costs == null || costs.length == 0) return 0; int N = costs.length, K = costs[0].length; int[][] dp = new int[N][K]; // Copy first row (base case) System.arraycopy(costs[0], 0, dp[0], 0, K); for (int i = 1; i < N; i++) { for (int c = 0; c < K; c++) { int minCost = Integer.MAX_VALUE; for (int prevC = 0; prevC < K; prevC++) { if (prevC != c) { minCost = Math.min(minCost, dp[i - 1][prevC]); } } dp[i] = costs[i] + minCost; } } // Return the minimum value from the last row int minCost = Integer.MAX_VALUE; for (int cost : dp[N - 1]) { minCost = Math.min(minCost, cost); } return minCost; } public static void main(String[] args) { int[][] costs = { {1, 3, 5}, {2, 9, 4}, {8, 3, 6}, {4, 7, 2} }; System.out.println(minCostToPaint(costs)); // Output: 8 } }
prevRow
) dp[N][K]
table, we store only the last row.public class PaintHousesOptimizedDP { public static int minCostToPaint(int[][] costs) { if (costs == null || costs.length == 0) return 0; int N = costs.length, K = costs[0].length; int[] prevRow = new int[K]; System.arraycopy(costs[0], 0, prevRow, 0, K); // Copy first row for (int i = 1; i < N; i++) { int[] currRow = new int[K]; for (int c = 0; c < K; c++) { int minCost = Integer.MAX_VALUE; for (int prevC = 0; prevC < K; prevC++) { if (prevC != c) { minCost = Math.min(minCost, prevRow[prevC]); } } currRow = costs[i] + minCost; } prevRow = currRow; } int minCost = Integer.MAX_VALUE; for (int cost : prevRow) { minCost = Math.min(minCost, cost); } return minCost; } public static void main(String[] args) { int[][] costs = { {1, 3, 5}, {2, 9, 4}, {8, 3, 6}, {4, 7, 2} }; System.out.println(minCostToPaint(costs)); // Output: 8 } }
min1
: Smallest cost in the previous row.min1Idx
: Index of min1
.min2
: Second smallest cost.min1Idx
, use min1
, otherwise use min2
.public class PaintHousesOptimal { public static int minCostToPaint(int[][] costs) { if (costs == null || costs.length == 0) return 0; int N = costs.length, K = costs[0].length; int min1 = 0, min1Idx = -1, min2 = 0; for (int i = 0; i < N; i++) { int newMin1 = Integer.MAX_VALUE, newMin1Idx = -1, newMin2 = Integer.MAX_VALUE; for (int c = 0; c < K; c++) { int cost = costs[i] + (c == min1Idx ? min2 : min1); if (cost < newMin1) { newMin2 = newMin1; newMin1 = cost; newMin1Idx = c; } else if (cost < newMin2) { newMin2 = cost; } } min1 = newMin1; min1Idx = newMin1Idx; min2 = newMin2; } return min1; } public static void main(String[] args) { int[][] costs = { {1, 3, 5}, {2, 9, 4}, {8, 3, 6}, {4, 7, 2} }; System.out.println(minCostToPaint(costs)); // Output: 8 } }
Approach | Time Complexity | Space Complexity |
---|---|---|
Brute Force | O(K^N) | O(N) |
DP Table | O(NK^2) | O(NK) |
Optimized DP | O(NK) | O(K) |
Fully Optimized | O(NK) | O(1) |
This final O(NK) time, O(1)space approach is the best possible solution. 🚀
Did this solution help you understand the concept better? Let me know your thoughts in the comments below! Don’t forget to follow us on Instagram @coderz.py for more DSA tips and solutions to ace your coding interviews.
Find the length of the longest absolute path to a file within the abstracted file…
You manage an e-commerce website and need to keep track of the last N order…
You are given a stream of elements that is too large to fit into memory.…
The formula for the area of a circle is given by πr². Use the Monte…
Given an integer k and a string s, write a function to determine the length…
There is a staircase with N steps, and you can ascend either 1 step or…