There is a row of m
houses in a small city, each house must be painted with one of the n
colors (labeled from 1
to n
), some houses that have been painted last summer should not be painted again.
A neighborhood is a maximal group of continuous houses that are painted with the same color.
houses = [1,2,2,3,3,2,1,1]
contains 5
neighborhoods [{1}, {2,2}, {3,3}, {2}, {1,1}]
.Given an array houses
, an m x n
matrix cost
and an integer target
where:
houses[i]
: is the color of the house i
, and 0
if the house is not painted yet.cost[i][j]
: is the cost of paint the house i
with the color j + 1
.Return the minimum cost of painting all the remaining houses in such a way that there are exactly target
neighborhoods. If it is not possible, return -1
.
Example 1:
Input: houses = [0,0,0,0,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3 Output: 9 Explanation: Paint houses of this way [1,2,2,1,1] This array contains target = 3 neighborhoods, [{1}, {2,2}, {1,1}]. Cost of paint all houses (1 + 1 + 1 + 1 + 5) = 9.
Example 2:
Input: houses = [0,2,1,2,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3 Output: 11 Explanation: Some houses are already painted, Paint the houses of this way [2,2,1,2,2] This array contains target = 3 neighborhoods, [{2,2}, {1}, {2,2}]. Cost of paint the first and last house (10 + 1) = 11.
Example 3:
Input: houses = [3,1,2,3], cost = [[1,1,1],[1,1,1],[1,1,1],[1,1,1]], m = 4, n = 3, target = 3 Output: -1 Explanation: Houses are already painted with a total of 4 neighborhoods [{3},{1},{2},{3}] different of target = 3.
Constraints:
m == houses.length == cost.length
n == cost[i].length
1 <= m <= 100
1 <= n <= 20
1 <= target <= m
0 <= houses[i] <= n
1 <= cost[i][j] <= 104
This problem asks for the minimum cost to paint a row of houses with n
color options, subject to constraints on the number of contiguous blocks of the same color (target
) and pre-existing paint (houses
). A dynamic programming approach is highly effective here.
The core idea is to build a 3D DP table f[i][j][k]
, where:
i
: Represents the house index (0 to m-1).j
: Represents the color of the house at index i
(1 to n).k
: Represents the number of neighborhoods (contiguous blocks of the same color) formed so far (1 to target
).f[i][j][k]
stores the minimum cost to paint houses 0 to i
such that the last house (i
) is painted color j
, and there are k
neighborhoods.
We iterate through houses. For each house i
:
Unpainted House (houses[i] == 0): We can choose any color j
. The cost depends on the previous house's color (j0
):
j == j0
, the number of neighborhoods remains the same (k
). The cost is f[i-1][j0][k] + cost[i][j-1]
.j != j0
, a new neighborhood starts, increasing the count to k
. The cost is f[i-1][j0][k-1] + cost[i][j-1]
.We take the minimum cost over all possible j0
.
Painted House (houses[i] != 0): The color j
is fixed to houses[i]
. We iterate through previous house colors j0
:
j == j0
, the neighborhood count remains k
. Cost is f[i-1][j0][k]
.j != j0
, a new neighborhood starts. Cost is f[i-1][j0][k-1]
.Again, we take the minimum over all j0
.
For i = 0
:
houses[0] == 0
, f[0][j][1] = cost[0][j-1]
for all colors j
.houses[0] != 0
, f[0][houses[0]][1] = 0
. (House is already painted).The final answer is the minimum of f[m-1][j][target]
for all colors j
, representing the minimum cost to paint all houses with target
neighborhoods. If this minimum is still infinity, it means no solution exists, so we return -1.
import sys
def minCost(houses, cost, m, n, target):
inf = sys.maxsize
dp = [[[inf] * (target + 1) for _ in range(n + 1)] for _ in range(m)]
# Base Case
if houses[0] == 0:
for j in range(1, n + 1):
dp[0][j][1] = cost[0][j - 1]
else:
dp[0][houses[0]][1] = 0
# DP Transition
for i in range(1, m):
for j in range(1, n + 1):
for k in range(1, min(target + 1, i + 2)): #k <= i+1 because at most i+1 neighborhoods are possible
for j0 in range(1, n + 1):
if houses[i] == 0:
new_cost = cost[i][j - 1]
else:
new_cost = 0 if houses[i] == j else inf
if j == j0:
dp[i][j][k] = min(dp[i][j][k], dp[i - 1][j0][k] + new_cost)
else:
dp[i][j][k] = min(dp[i][j][k], dp[i - 1][j0][k - 1] + new_cost)
# Result
ans = min(dp[m - 1][j][target] for j in range(1, n + 1))
return -1 if ans == inf else ans
The code in other languages (Java, C++, Go, TypeScript) follows a very similar structure, implementing the same DP logic with minor syntactic variations. The key is the 3D DP table and the careful consideration of the state transitions based on whether a house is already painted or not.