leetcode-剑指 Offer II 091. 粉刷房子

80 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情

题目描述

假如有一排房子,共 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
 

提示:

  • costs.length == n
  • costs[i].length == 3
  • 1 <= n <= 100
  • 1 <= costs[i][j] <= 20

思路

首先理解题意,如果没有“相邻的两个房子颜色不能相同”的限制,可以直接贪心每次取花费最小的油漆就好。一般的,我们令函数f(x)代表[0, x]号房子粉刷完的最小花费成本,那么我们在推导f(x+1)的时候,序号为x的房子的颜色是有关的,因为x+1不能跟x使用同一种颜色,但是f(x)并不能表达出x号房子的颜色。所以我们这里可以开3个数组,red、blue、green,分别代表x的房子粉刷成红蓝绿色时,[0, x]号房子粉刷完的最小花费成本。我们的递推red[x+1]的时候,那么x的房子肯定不能是红色,否则就连续2个红色房子了,x可以是蓝色或者绿色,所以我们可以得到递推公式:

red[x+1] = costs[x+1][0] + Integer.min(blue[x], green[x]);
blue[x+1] = costs[x+1][1] + Integer.min(red[x], green[x]);
green[x+1] = costs[x+1][2] + Integer.min(red[x], blue[x]);

初始值,对于0号房子来说,前面没有房子,所以3中颜色都是可以的

red[0] = costs[0][0];
blue[0] = costs[0][1];
green[0] = costs[0][2];

Java版本代码

class Solution {
    public int minCost(int[][] costs) {
        int len = costs.length;
        int[] red = new int[len];
        int[] blue = new int[len];
        int[] green = new int[len];
        red[0] = costs[0][0];
        blue[0] = costs[0][1];
        green[0] = costs[0][2];
        for (int i = 1; i < len; i++) {
            red[i] = costs[i][0] + Integer.min(blue[i-1], green[i-1]);
            blue[i] = costs[i][1] + Integer.min(red[i-1], green[i-1]);
            green[i] = costs[i][2] + Integer.min(red[i-1], blue[i-1]);
        }
        return Integer.min(red[len-1], Integer.min(blue[len-1], green[len-1]));
    }
}