原题网址:https://leetcode.com/problems/paint-house-ii/
There are a row of n houses, each house can be painted with one of the k colors. The cost of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent houses have the same color.
The cost of painting each house with a certain color is represented by a n x k
cost matrix. For example, costs[0][0]
is the cost of painting house 0 with color 0; costs[1][2]
is the cost of painting house 1 with color 2, and so on... Find the minimum cost to paint all houses.
Note:
All costs are positive integers.
Follow up:
Could you solve it in O(nk) runtime?
方法:动态规划,求出最低成本和次低成本,如果房子的颜色和上一个房子最低成本的颜色相同,则涂上次低成本的颜色,否则涂最低成本的颜色。
这道题不需要我们分别求出与每一个颜色不同的最低成本值,只需要求出最低和次低,就可以有效避免颜色间隔的问题,这是关键。
public class Solution {
private void find(int[] cost, int[] min, int[] color) {
color[0] = -1;
color[1] = -1;
for(int i=0; i<cost.length; i++) {
if (color[0] == -1 || cost[i] < min[0]) {
min[0] = cost[i];
color[0] = i;
}
}
for(int i=0; i<cost.length; i++) {
if (i != color[0] && (color[1] == -1 || cost[i] < min[1])) {
min[1] = cost[i];
color[1] = i;
}
}
}
public int minCostII(int[][] costs) {
if (costs == null || costs.length == 0) return 0;
int[] minCost = new int[2];
int[] color = new int[2];
int[] nextMinCost = new int[2];
int[] nextColor = new int[2];
find(costs[0], minCost, color);
for(int i=1; i<costs.length; i++) {
for(int j=0; j<costs[i].length; j++) {
costs[i][j] += j!=color[0] ? minCost[0] : minCost[1];
}
find(costs[i], nextMinCost, nextColor);
int[] t1 = minCost;
minCost = nextMinCost;
nextMinCost = t1;
int[] t2 = color;
color = nextColor;
nextColor = t2;
}
return minCost[0];
}
}
可以进一步优化得更简洁:
public class Solution {
// 求出最低成本和次低成本
private void mins(int[] cost, int[] min) {
for(int i=0; i<cost.length; i++) {
if (i==0 || cost[i] < cost[min[0]]) min[0] = i;
}
if (min[0] == 0) min[1] = 1; else min[1] = 0;
for(int i=0; i<cost.length; i++) {
if (i != min[0] && cost[i] < cost[min[1]]) min[1] = i;
}
}
public int minCostII(int[][] costs) {
if (costs == null || costs.length == 0) return 0;
int[] minCost = new int[costs[0].length];
int[] min = new int[2];
for(int c=0; c<costs[0].length; c++) {
minCost[c] = costs[0][c];
}
mins(minCost, min);
for(int h=1; h<costs.length; h++) {
int[] prevCost = minCost;
minCost = new int[costs[0].length];
for(int c=0; c<costs[h].length; c++) {
if (c != min[0]) minCost[c] = prevCost[min[0]] + costs[h][c];
else minCost[c] = prevCost[min[1]] + costs[h][c];
}
mins(minCost, min);
}
return minCost[min[0]];
}
}
如果不分成两个步骤,即先计算每种颜色的最低成本,在寻找最低成本的两种颜色,就会比较罗嗦:
public class Solution {
public int minCostII(int[][] costs) {
if (costs == null || costs.length == 0 || costs[0].length == 0) return 0;
int n = costs.length;
int k = costs[0].length;
int[][] mins = new int[n][2];
int[][] colors = new int[n][2];
for(int j=0; j<k; j++) {
if (mins[0][0] == 0 || costs[0][j] < mins[0][0]) {
colors[0][0] = j;
mins[0][0] = costs[0][j];
}
}
for(int j=0; j<k; j++) {
if (j==colors[0][0]) continue;
if (mins[0][1] == 0 || costs[0][j] < mins[0][1]) {
colors[0][1] = j;
mins[0][1] = costs[0][j];
}
}
for(int i=1; i<n; i++) {
// generate minimum
for(int j=0; j<k; j++) {
if (j!=colors[i-1][0]) {
if (mins[i][0] == 0 || mins[i-1][0] + costs[i][j] < mins[i][0]) {
colors[i][0] = j;
mins[i][0] = mins[i-1][0] + costs[i][j];
}
} else {
if (mins[i][0] == 0 || mins[i-1][1] + costs[i][j] < mins[i][0]) {
colors[i][0] = j;
mins[i][0] = mins[i-1][1] + costs[i][j];
}
}
}
// generate second minimum
for(int j=0; j<k; j++) {
if (j==colors[i][0]) continue;
if (j!=colors[i-1][0]) {
if (mins[i][1] == 0 || mins[i-1][0] + costs[i][j] < mins[i][1]) {
colors[i][1] = j;
mins[i][1] = mins[i-1][0] + costs[i][j];
}
} else {
if (mins[i][1] == 0 || mins[i-1][1] + costs[i][j] < mins[i][1]) {
colors[i][1] = j;
mins[i][1] = mins[i-1][1] + costs[i][j];
}
}
}
}
return mins[n-1][0];
}
}