 
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:
- Each row represents a house (n), and
- Each column represents a color (k).
- The value at matrix[n][k]indicates the cost to paint housenwith colork.
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.
Brute Force Approach: O(K^N) Time Complexity
Step-by-Step Explanation
- Try Every Possible Combination of Colors
- For each house, try every possible color.
- Ensure that no two adjacent houses have the same color.
- Compute the cost for each valid combination.
 
- Inefficiency
- Exponential Growth: O(K^N) due to recursive branching.
- Overlapping Subproblems: Redundant calculations for different color choices.
 
Java Code (Brute Force Recursive)
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)
    }
}
Dynamic Programming Approach (O(NK²) Time Complexity)
Step-by-Step Explanation
- Define DP Matrix (dp[i])- Represents minimum cost to paint house iii with color ccc.
 
- Transition Formula- Compute the cost for house iii by taking the minimum cost of painting previous houses, excluding the current color.
 
- Final Result
- The answer is the minimum value in the last row.
 
Java Code (O(NK²) DP Solution)
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
    }
}
Optimized DP Approach (O(NK) Time Complexity, O(K) Space)
Step-by-Step Explanation
- Track Only the Last Row (prevRow)- Instead of keeping a full dp[N][K]table, we store only the last row.
 
- Instead of keeping a full 
- Transition Formula
- Compute minimum values of the previous row.
- Update the current row based on previous minimum cost values.
 
- Final Result
- Return the minimum value from the last computed row.
 
Java Code (Optimized O(NK) Space Solution)
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
    }
}
Final Optimized Approach (O(NK) Time Complexity, O(1) Space)
Step-by-Step Explanation
- Track Only Three Variables
- min1: Smallest cost in the previous row.
- min1Idx: Index of- min1.
- min2: Second smallest cost.
 
- Use Efficient Update Rule
- If the color is not min1Idx, usemin1, otherwise usemin2.
 
- If the color is not 
Java Code (Fully Optimized O(NK) Time, O(1) Space)
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
    }
}
Final Complexity Comparison
| 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.
Leave a Comment
You must be logged in to post a comment.