256. 粉刷房子

256. 粉刷房子

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

解法一:标准 DP

思想

状态表示:

  1. f[i][0] 表示第 i 次刷红和前 i - 1 次累计花费
  2. f[i][1] 表示第 i 次刷蓝和前 i - 1 次累计花费
  3. f[i][2] 表示第 i 次刷绿和前 i - 1 次累计花费

属性计算:最小花费,即 min

状态转移:

  1. 对于 1 来说,这次刷红,前一次只能刷蓝或绿,即只能从 f[i - 1][1]f[i - 1][2] 转移
  2. 对于 2 来说,这次刷蓝,前一次只能刷红或绿,即只能从 f[i - 1][0]f[i - 1][2] 转移
  3. 对于 3 来说,这次刷绿,前一次只能刷红或蓝,即只能从 f[i - 1][1]f[i - 1][2] 转移

复杂度

时间复杂度: O ( N ) O(N) O(N),需要计算前 N − 1 N-1 N1 次最低花费,才能确定最终最低花费

空间复杂度: O ( N ) O(N) O(N),需要记录前 N − 1 N - 1 N1 种状态

代码

class Solution {
    public int minCost(int[][] costs) {
        int n = costs.length;
        int[][] f = new int[n + 1][3];
        for (int i = 1; i <= n; i++) {
            f[i][0] = Math.min(f[i - 1][1], f[i - 1][2]) + costs[i - 1][0];
            f[i][1] = Math.min(f[i - 1][0], f[i - 1][2]) + costs[i - 1][1];
            f[i][2] = Math.min(f[i - 1][0], f[i - 1][1]) + costs[i - 1][2];
        }
        return Math.min(f[n][0], Math.min(f[n][1], f[n][2]));
    }
}

解法二:滚动变量优化

思想

f[i][0] = Math.min(f[i - 1][1], f[i - 1][2]) + costs[i - 1][0];
f[i][1] = Math.min(f[i - 1][0], f[i - 1][2]) + costs[i - 1][1];
f[i][2] = Math.min(f[i - 1][0], f[i - 1][1]) + costs[i - 1][2];

发现只与 i - 1 层有关,于是可以用两组 3 个变量滚动更新。

复杂度

时间复杂度: O ( N ) O(N) O(N),需要计算前 N − 1 N-1 N1 次最低花费,才能确定最终最低花费

空间复杂度: O ( 1 ) O(1) O(1),利用常数个变量滚动更新记录状态

代码

class Solution {
    public int minCost(int[][] costs) {
        int n = costs.length;
        int a = 0, b = 0, c = 0;
        for (int i = 1; i <= n; i++) {
            int x = a, y = b, z = c;
            a = Math.min(y, z) + costs[i - 1][0];
            b = Math.min(x, z) + costs[i - 1][1];
            c = Math.min(x, y) + costs[i - 1][2];
        }
        return Math.min(a, Math.min(b, c));
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值