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.
You are given two singly linked lists that intersect at some node. Your task is…
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…