假如有一排房子,共 n 个,每个房子可以被粉刷成红色、蓝色或者绿色这三种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。
当然,因为市场上不同颜色油漆的价格不同,所以房子粉刷成不同颜色的花费成本也是不同的。每个房子粉刷成不同颜色的花费是以一个 n x 3 的正整数矩阵 costs 来表示的。
例如,costs[ 0 ] [ 0 ] 表示第 0 号房子粉刷成红色的成本花费;costs[ 1 ] [ 2 ] 表示第 1 号房子粉刷成绿色的花费,以此类推。
请计算出粉刷完所有房子最少的花费成本。
示例 1 :
输入: costs = [ [ 17 , 2 , 17 ] , [ 16 , 16 , 5 ] , [ 14 , 3 , 19 ] ]
输出: 10
解释: 将 0 号房子粉刷成蓝色,1 号房子粉刷成绿色,2 号房子粉刷成蓝色。
最少花费: 2 + 5 + 3 = 10 。
示例 2 :
输入: costs = [ [ 7 , 6 , 2 ] ]
输出: 2
在练习动态规划的题目时,千万别一上来就想当然地写状态转移方程然后尝试去解释它的可行性,也千万别看题解的时候直接看状态转移方程。因为状态转移方程是推导出来的,推导的过程远比结论要重要。就跟数学一样,一个公式只知道怎么用不牛逼,知道怎么推出来的,知道怎么举一反三才是最牛逼的。这也是为什么动态规划的题目,即使是Hard也有人吐槽简单,即使是Middle也有大把人不会,因为当你理解了状态转移方程的那一刻,题目就变得非常简单了,而如果你不知道状态转移方程,那题目就会变得很难。
下面说说这道题目的动态规划思路,我们依次粉刷房子,而每次粉刷的颜色只跟上一间房子有关。如果当前房子想要刷红色,那么前一间房子只能是蓝色或者绿色,那么当前房子刷红色的最低花费就是 Math. min ( 前一间房子刷蓝色的最低花费,前一间房子刷绿色的最低花费) + 当前房子刷红色的成本。其余颜色以此类推,到这里转移方程就比较清晰了,最后请你试一试将上面的语言用数学的符号表示。
class Solution {
public int minCost ( int [ ] [ ] costs) {
int n = costs. length;
int [ ] [ ] dp = new int [ n] [ 3 ] ;
dp[ 0 ] [ 0 ] = costs[ 0 ] [ 0 ] ;
dp[ 0 ] [ 1 ] = costs[ 0 ] [ 1 ] ;
dp[ 0 ] [ 2 ] = costs[ 0 ] [ 2 ] ;
for ( int i = 1 ; i < n; i++ ) {
dp[ i] [ 0 ] = Math. min ( dp[ i - 1 ] [ 1 ] , dp[ i - 1 ] [ 2 ] ) + costs[ i] [ 0 ] ;
dp[ i] [ 1 ] = Math. min ( dp[ i - 1 ] [ 0 ] , dp[ i - 1 ] [ 2 ] ) + costs[ i] [ 1 ] ;
dp[ i] [ 2 ] = Math. min ( dp[ i - 1 ] [ 0 ] , dp[ i - 1 ] [ 1 ] ) + costs[ i] [ 2 ] ;
}
return Math. min ( dp[ n - 1 ] [ 0 ] , Math. min ( dp[ n - 1 ] [ 1 ] , dp[ n - 1 ] [ 2 ] ) ) ;
}
}
下面是递归树, 这样的二维dp其实是算出了所有的可能! [ 在这里插入图片描述] ( https: