|
| 1 | +--- |
| 2 | +title: "265. Paint House II" |
| 3 | +date: "2025-10-08" |
| 4 | +tags: ["Dynamic Programming", "Array"] |
| 5 | +related: [] |
| 6 | +slug: "265-paint-house-ii" |
| 7 | +category: "leetcode" |
| 8 | +leetcode_url: "https://leetcode.com/problems/paint-house-ii/description/?envType=problem-list-v2&envId=xxzz5vc6" |
| 9 | +leetcode_difficulty: "Hard" |
| 10 | +leetcode_topics: ["Dynamic Programming", "Array"] |
| 11 | +--- |
| 12 | + |
| 13 | +# 265. Paint House II |
| 14 | + |
| 15 | +## Summary |
| 16 | +Given n houses and k colors, find the minimum cost to paint all houses such that no two adjacent houses have the same color, using dynamic programming with O(n*k) time and O(1) space optimization. |
| 17 | + |
| 18 | +## Problem Description |
| 19 | +There are a row of `n` houses, each house can be painted with one of `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. |
| 20 | + |
| 21 | +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 `0`; `costs[1][2]` is the cost of painting house `1` with color `2`, and so on. |
| 22 | + |
| 23 | +Return the minimum cost to paint all houses. |
| 24 | + |
| 25 | +**Constraints:** |
| 26 | +- `1 <= n <= 100` |
| 27 | +- `1 <= k <= 20` |
| 28 | +- `1 <= costs[i][j] <= 20` |
| 29 | + |
| 30 | +## Solution Approach |
| 31 | +This is a classic dynamic programming problem that can be solved with two approaches: |
| 32 | + |
| 33 | +### Approach 1: Standard DP (O(n*k) time, O(n*k) space) |
| 34 | +**Key Insight:** Use DP where `dp[i][j]` represents the minimum cost to paint first i houses, with house i-1 painted color j. |
| 35 | + |
| 36 | +**Algorithm:** |
| 37 | +1. `dp[i][j] = costs[i][j] + min(dp[i-1][k] for all k != j)` |
| 38 | +2. For each house i and color j, find the minimum cost from previous row excluding the same color j |
| 39 | +3. Final answer is `min(dp[n-1])` |
| 40 | + |
| 41 | +### Approach 2: Optimized DP (O(n*k) time, O(1) space) |
| 42 | +**Key Insight:** Instead of storing entire DP table, track the minimum and second minimum costs from previous row. |
| 43 | + |
| 44 | +**Algorithm:** |
| 45 | +1. For each house, calculate new minimum and second minimum costs |
| 46 | +2. For each color j, the cost is `costs[i][j] + (min1 if j != prev_min_color else min2)` |
| 47 | +3. Update min1, min2, and prev_min_color for next iteration |
| 48 | + |
| 49 | +## Time & Space Complexity |
| 50 | +- **Time Complexity:** O(n*k) for both approaches |
| 51 | +- **Space Complexity:** O(n*k) for standard DP, O(1) for optimized DP |
| 52 | + |
| 53 | +## Key Insights |
| 54 | +- **Color constraint**: Adjacent houses cannot have same color |
| 55 | +- **Optimization trick**: Track min1 and min2 from previous row to avoid O(k) search for each color |
| 56 | +- **Edge case handling**: When k=1, houses must use different colors but only one available (impossible if n>1) |
| 57 | +- **Small constraints**: n<=100, k<=20 makes O(n*k^2) acceptable but we can optimize to O(n*k) |
| 58 | + |
| 59 | +## Examples / snippets |
| 60 | + |
| 61 | +### Solution Code (Optimized DP) |
| 62 | +```python |
| 63 | +from typing import List |
| 64 | + |
| 65 | +class Solution: |
| 66 | + def minCostII(self, costs: List[List[int]]) -> int: |
| 67 | + if not costs or not costs[0]: |
| 68 | + return 0 |
| 69 | + |
| 70 | + n, k = len(costs), len(costs[0]) |
| 71 | + |
| 72 | + # Initialize with first house costs |
| 73 | + prev_min1 = prev_min2 = float('inf') |
| 74 | + prev_min_color = -1 |
| 75 | + |
| 76 | + for j in range(k): |
| 77 | + if costs[0][j] < prev_min1: |
| 78 | + prev_min2 = prev_min1 |
| 79 | + prev_min1 = costs[0][j] |
| 80 | + prev_min_color = j |
| 81 | + elif costs[0][j] < prev_min2: |
| 82 | + prev_min2 = costs[0][j] |
| 83 | + |
| 84 | + # Process remaining houses |
| 85 | + for i in range(1, n): |
| 86 | + curr_min1 = curr_min2 = float('inf') |
| 87 | + curr_min_color = -1 |
| 88 | + |
| 89 | + for j in range(k): |
| 90 | + # Choose the minimum cost from previous row |
| 91 | + cost = costs[i][j] + (prev_min2 if j == prev_min_color else prev_min1) |
| 92 | + |
| 93 | + if cost < curr_min1: |
| 94 | + curr_min2 = curr_min1 |
| 95 | + curr_min1 = cost |
| 96 | + curr_min_color = j |
| 97 | + elif cost < curr_min2: |
| 98 | + curr_min2 = cost |
| 99 | + |
| 100 | + prev_min1, prev_min2, prev_min_color = curr_min1, curr_min2, curr_min_color |
| 101 | + |
| 102 | + return prev_min1 |
| 103 | +``` |
| 104 | + |
| 105 | +### Solution Code (Standard DP) |
| 106 | +```python |
| 107 | +from typing import List |
| 108 | + |
| 109 | +class Solution: |
| 110 | + def minCostII(self, costs: List[List[int]]) -> int: |
| 111 | + if not costs or not costs[0]: |
| 112 | + return 0 |
| 113 | + |
| 114 | + n, k = len(costs), len(costs[0]) |
| 115 | + dp = [[float('inf')] * k for _ in range(n)] |
| 116 | + |
| 117 | + # First house - can use any color |
| 118 | + for j in range(k): |
| 119 | + dp[0][j] = costs[0][j] |
| 120 | + |
| 121 | + # Fill DP table |
| 122 | + for i in range(1, n): |
| 123 | + for j in range(k): |
| 124 | + # Find minimum cost from previous row, excluding same color |
| 125 | + min_prev = float('inf') |
| 126 | + for prev_j in range(k): |
| 127 | + if prev_j != j: |
| 128 | + min_prev = min(min_prev, dp[i-1][prev_j]) |
| 129 | + |
| 130 | + dp[i][j] = costs[i][j] + min_prev |
| 131 | + |
| 132 | + # Return minimum cost for last house |
| 133 | + return min(dp[n-1]) |
| 134 | +``` |
| 135 | + |
| 136 | +### Example Walkthrough |
| 137 | +**Example 1:** |
| 138 | +``` |
| 139 | +Input: costs = [[1,5,3],[2,9,4]] |
| 140 | +Output: 5 |
| 141 | +
|
| 142 | +Explanation: |
| 143 | +House 0: Paint with color 0 (cost 1), color 1 (cost 5), or color 2 (cost 3) |
| 144 | +House 1: Paint with color 0 (cost 2), color 1 (cost 9), or color 2 (cost 4) |
| 145 | +
|
| 146 | +DP Table: |
| 147 | +House 0: [1, 5, 3] |
| 148 | +House 1: [2+min(5,3)=5, 9+min(1,3)=4, 4+min(1,5)=5] = [5, 4, 5] |
| 149 | +
|
| 150 | +Minimum cost: 4 (house 0 color 2, house 1 color 1) |
| 151 | +
|
| 152 | +Optimized approach: |
| 153 | +- After house 0: min1=1 (color 0), min2=3 (color 2) |
| 154 | +- For house 1, color 0: 2 + 3 = 5 (since color 0 != prev min color 0, use min2=3) |
| 155 | +- For house 1, color 1: 9 + 1 = 10 (use min1=1) |
| 156 | +- For house 1, color 2: 4 + 1 = 5 (since color 2 == prev min color 2, use min2=3? Wait no) |
| 157 | +
|
| 158 | +Wait, let me recalculate properly: |
| 159 | +- After house 0: min1=1 (color 0), min2=3 (color 2), prev_min_color=0 |
| 160 | +- For house 1, color 0: 2 + min2 = 2 + 3 = 5 (j=0 == prev_min_color=0, so use min2) |
| 161 | +- For house 1, color 1: 9 + min1 = 9 + 1 = 10 (j=1 != prev_min_color=0, so use min1) |
| 162 | +- For house 1, color 2: 4 + min1 = 4 + 1 = 5 (j=2 != prev_min_color=0, so use min1) |
| 163 | +
|
| 164 | +So we get [5, 10, 5], minimum is 5 ✓ |
| 165 | +``` |
| 166 | + |
| 167 | +**Example 2:** |
| 168 | +``` |
| 169 | +Input: costs = [[1,3],[2,4]] |
| 170 | +Output: 5 |
| 171 | +
|
| 172 | +Explanation: |
| 173 | +- Paint house 0 with color 1 (cost 3) |
| 174 | +- Paint house 1 with color 0 (cost 2) |
| 175 | +- Total cost: 3 + 2 = 5 |
| 176 | +
|
| 177 | +Alternative: house 0 color 0 (1) + house 1 color 1 (4) = 5, same result. |
| 178 | +``` |
| 179 | + |
| 180 | +## Edge Cases & Validation |
| 181 | +- **Single house**: Return minimum cost among all colors for that house |
| 182 | +- **Two houses**: Standard DP works fine |
| 183 | +- **k = 1**: If n > 1, impossible (return appropriate value based on constraints) |
| 184 | +- **All costs same**: Should work correctly with DP |
| 185 | +- **Minimum cost is 0**: Edge case where some costs are 0 |
| 186 | +- **Large n, small k**: Should handle n=100, k=20 efficiently |
| 187 | + |
| 188 | +## Related Problems |
| 189 | +- [256. Paint House](https://leetcode.com/problems/paint-house/) - Similar but with only 3 colors (can be O(1) space) |
| 190 | +- [1473. Paint House III](https://leetcode.com/problems/paint-house-iii/) - More complex version with street constraints |
| 191 | +- [265. Paint House II](https://leetcode.com/problems/paint-house-ii/) - This problem |
| 192 | +- [Dynamic Programming Patterns](https://leetcode.com/tag/dynamic-programming/) - General DP practice |
| 193 | +``` |
0 commit comments