题目地址:
https://www.lintcode.com/problem/paint-house-ii/description
给定一个二维数组,长 n n n宽 k k k,每一行是当前行的房子涂第 k k k种漆所花费的成本。要求相邻的房子不能涂同种颜色的漆。问涂完这 n n n个房子花费的最小成本是多少。
思想是动态规划,如果已知到前一个房子为止,在前一个房子涂每种油漆的情况下所有前面房子涂漆的最小成本的话,我们就可以递推一步得到当前的房子为止的最小成本。为了降低复杂度,我们需要记录一下前一个房子为止涂各个颜色的最小成本和次小成本,这样在更新当前房子的时候,在考虑第 j j j种颜色的时候,只需要比较一下前一个房子为止涂第 j j j种颜色的成本是否大于那个最小成本,如果大于,说明此房子可以涂第 j j j种颜色(因为最小成本的最后一个房子的颜色必然不是第 j j j种颜色);否则此房子涂第 j j j种颜色时前面房子的最小成本是那个次小成本。为了节省空间,我们还可以做滚动数组优化。代码如下:
import java.util.Arrays;
public class Solution {
/**
* @param costs: n x k cost matrix
* @return: an integer, the minimum cost to paint all houses
*/
public int minCostII(int[][] costs) {
// write your code here
// 特判
if (costs == null || costs.length == 0 || costs[0].length == 0) {
return 0;
}
// n代表有多少房子,k代表有多少种颜色
int n = costs.length, k = costs[0].length;
// cost用来记录各个颜色下,当前房子为止的最小成本和上一个房子为止的最小成本
int[][] cost = new int[2][k];
// 初始化第一个房子的情形
for (int i = 0; i < k; i++) {
cost[0][i] = costs[0][i];
}
// ind用来做滚动数组时记录当前更新的和过去更新的下标
int ind = 0;
// minCosts记录过去更新的成本中最小和次小成本
int[] minCosts = new int[2];
for (int i = 1; i < n; i++) {
// 首先初始化一下最小成本为正无穷
minCosts[0] = minCosts[1] = Integer.MAX_VALUE;
for (int j = 0; j < k; j++) {
// 如果找到比最小值还小的,就把最小值赋值给次小值,然后更新最小值
if (cost[ind][j] < minCosts[0]) {
minCosts[1] = minCosts[0];
minCosts[0] = cost[ind][j];
} else if (cost[ind][j] < minCosts[1]) {
// 否则的话,如果找到比次小值小的,就更新次小值
minCosts[1] = cost[ind][j];
}
}
for (int j = 0; j < k; j++) {
// 如果前一个房子涂第j种颜色的情况下前一个房子为止的最小成本大于全局最小成本,
// 说明当前房子可以涂前一个房子涂的颜色,直接更新
if (cost[ind][j] > minCosts[0]) {
cost[ind ^ 1][j] = minCosts[0] + costs[i][j];
} else {
// 如果前一个房子涂第j种颜色的情况下前一个房子为止的最小成本等于全局最小成本,
// 说明当前房子涂第j种颜色的时候,前面的房子只能选次小成本的方案
cost[ind ^ 1][j] = minCosts[1] + costs[i][j];
}
}
// 滚动一下下标。注意ind在循环结束时,永远是最新更新的那个下标
ind ^= 1;
}
// 扫描一遍最终结果,返回最小值
int res = Integer.MAX_VALUE;
for (int i = 0; i < k; i++) {
res = Math.min(res, cost[ind][i]);
}
return res;
}
}
时间复杂度 O ( n k ) O(nk) O(nk),空间 O ( k ) O(k) O(k)。