假如有一排房子,共 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.
首先,我们考虑到直观的动态规划。
就是第一行找到最优最小值,然后递归到第二行,递归到第三行,但是这道题显然不行,由于第一行选择会限制第二行选择。
因此换一种思路,将上一行所有的情况暂存(包括最优值),纳入下一行考察范围内,然后筛选掉非最优值。
ps:这里还有优化空间,待会讨论。
我们找到一个 O(n*k^2) 的动态规划解法,这个解法就是粉刷房子 解法的一个简单扩展。建立一个二维数组dp[i][k],其中i表示前i座房子,k表示该房子粉刷成颜色k的情况下前i座房子的最小花费,易得状态转移方程:
dp[i][k] = Math.min(dp[i-1][m]) + costs[i][k]
m取值范围是为[0, k-1], [k+1, costs[i].length-1即costs数组列数]
python3实现:
class Solution:
def minCostII(self, costs: List[List[int]]) -> int:
if not(costs):
return 0
dp=[]
row=len(costs)
col=len(costs[0])
dp=[[] for i in range(row)]
helper=[]
for i in range(col):
helper.append(float('inf'))
for i in range(row):
for j in range(col):
helper[j]=(float('inf'))
if i==0:
dp[i].append(costs[0][j])
else:
k=j
for m in range(k):
helper[m]=(dp[i-1][m])+costs[i][k]
for m in range(k+1,col):
helper[m]=(dp[i-1][m])+costs[i][k]
dp[i].append(min(helper))
return min(dp[row-1])
更好的优化建议:实际上,下一行只会受到上一行最小值和次小值的影响,可以通过减少helper写入次数来优化算法。
思路来源:
作者:ellery0924
链接:https://leetcode-cn.com/problems/two-sum/solution/javascript-onkfu-za-du-jie-fa-by-ellery0924/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。