1、题目描述
同类题:LeetCode256. 粉刷房子 https://blog.csdn.net/IOT_victor/article/details/106365741 (序列型)
假如有一排房子,共 n 个,每个房子可以被粉刷成 k 种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。
当然,因为市场上不同颜色油漆的价格不同,所以房子粉刷成不同颜色的花费成本也是不同的。每个房子粉刷成不同颜色的花费是以一个 n x k 的矩阵来表示的。
例如,costs[0][0] 表示第 0 号房子粉刷成 0 号颜色的成本花费;costs[1][2] 表示第 1 号房子粉刷成 2 号颜色的成本花费,以此类推。请你计算出粉刷完所有房子最少的花费成本。注意:所有花费均为正整数。
输入: [[1,5,3],[2,9,4]]
输出: 5
解释: 将 0 号房子粉刷成 0 号颜色,1 号房子粉刷成 2 号颜色。最少花费: 1 + 4 = 5;
或者将 0 号房子粉刷成 2 号颜色,1 号房子粉刷成 0 号颜色。最少花费: 3 + 2 = 5.
进阶:您能否在 O(nk) 的时间复杂度下解决此问题?
2、代码详解
class Solution(object):
def minCostII(self, costs):
"""
:type costs: List[List[int]]
:rtype: int
"""
if not costs:
return 0
n = len(costs) # 房子数 n
k = len(costs[0]) # 颜色数 k
INF = float('inf')
dp = [[INF for _ in range(k)] for _ in range(n+1)]
# init
for i in range(k):
dp[0][i] = 0
id1, id2 = 0, 0 # 最小值和次小值的下标
for i in range(1, n+1):
min1 = INF # 花费最小值,记录之前的dp,同时用 id1 记录 j 时的颜色
min2 = INF # 花费次小值
for j in range(k): # 找到上一个状态[i-1]的花费最小数和次小数
if dp[i-1][j] < min1:
min2 = min1 # 将最小值 传给次小值
id2 = id1
min1 = dp[i-1][j]
id1 = j
else:
if dp[i-1][j] < min2:
min2 = dp[i-1][j]
id2 = j
for j in range(k):
dp[i][j] = costs[i-1][j] # 当前房子的花费,注意对齐下标,dp是n+1维,costs是n维
if j != id1: # 与上个状态最后的房子 不撞色,选最小值min1
dp[i][j] += min1
else: # 与上个状态最后的房子 撞色,选次小值min2
dp[i][j] += min2
# res = INF
# for i in range(k):
# res = min(res, dp[n][i])
res = min(dp[n][:])
return res
costs = [[14,2,11],[11,14,5],[14,3,10]] # 三个屋子分别使用第1,2,1种颜色,花费2+5+3,总花费是10
s = Solution()
print(s.minCostII(costs))
优化:从O(NK*K)到O(NK),记录最小值和次小值
https://www.jiuzhang.com/solutions/paint-house-ii/#tag-highlight-lang-python