1 中文题目
假如有一排房子共有 n
幢,每个房子可以被粉刷成 k
种颜色中的一种。房子粉刷成不同颜色的花费成本也是不同的。需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。
每个房子粉刷成不同颜色的花费以一个 n x k
的矩阵表示。
例如,costs[0][0] 表示第 0 幢房子粉刷成 0 号颜色的成本;costs[1][2] 表示第 1 幢房子粉刷成 2
号颜色的成本,以此类推。
返回 粉刷完所有房子的最低成本
。
示例:
输入: costs = [[1,5,3],[2,9,4]]
输出: 5
解释:
将房子 0 刷成 0 号颜色,房子 1 刷成 2 号颜色。花费: 1 + 4 = 5;
或者将 房子 0 刷成 2 号颜色,房子 1 刷成 0 号颜色。花费: 3 + 2 = 5.
输入: costs = [[1,3],[2,4]]
输出: 5
提示:
costs.length == n
costs[i].length == k
- 1 ≤ n ≤ 100 1 \leq n\leq 100 1≤n≤100
- 2 ≤ k ≤ 20 2 \leq k \leq 20 2≤k≤20
- 1 ≤ c o s t s [ i ] [ j ] ≤ 20 1 \leq costs[i][j] \leq 20 1≤costs[i][j]≤20
进阶: 在 O(nk) 的时间复杂度下解决此问题
2 Python求解
2.1 求解思路
使用动态规划解决粉刷房子问题,对每个房子,根据上一个房子的最小花费和次小花费来更新当前房子的花费,同时确保相邻房子颜色不同。通过维护最小值和次小值避免了对每个颜色都需要遍历所有其他颜色的情况。
2.2 涉及方法
- 动态规划(Dynamic Programming)结合状态压缩。动态规划用于构建最优解,每个状态表示粉刷到当前房子时的最小花费;通过只记录上一行的最小值和次小值来压缩状态,优化时间复杂度。
2.3 求解示例
以costs = [[1,5,3],[2,9,4]]为例:
初始状态:第一排房子花费[1,5,3]
处理第二排房子:
找出第一排的最小值(1,索引0)和次小值(3)
更新第二排每个颜色的花费:
j=0: 2+3=5(使用次小值,因为索引相同)
j=1: 9+1=10
j=2: 4+1=5
最终返回第二排的最小值:min(5,10,5)=5
2.4 Python代码
class Solution:
def minCostII(self, costs: List[List[int]]) -> int:
# 如果没有房子需要粉刷,返回0
if not costs:
return 0
n, k = len(costs), len(costs[0])
# 遍历每个房子
for i in range(1, n):
# 找出上一行的最小值和次小值及其对应的颜色索引
min1 = min2 = float('inf') # 最小值和次小值
idx1 = 0 # 最小值的索引
# 遍历上一个房子的所有颜色花费
for j in range(k):
cost = costs[i-1][j]
# 更新最小值和次小值
if cost < min1:
min2 = min1
min1 = cost
idx1 = j
elif cost < min2:
min2 = cost
# 更新当前房子的所有颜色花费
# 如果当前颜色与上一个最小值的颜色相同,就用次小值
# 否则用最小值
for j in range(k):
costs[i][j] += min2 if j == idx1 else min1
# 返回最后一行的最小值
return min(costs[-1])
2.5 复杂度分析
- 时间复杂度为O(nk),其中n是房子数量,k是颜色数量,每个房子只需要遍历一次所有颜色。
- 空间复杂度为O(1),因为直接在输入数组上修改,只需要常数额外空间存储最小值和次小值。
3 题目总结
题目难度:困难
数据结构:数组
应用算法:动态规划