【DP】LeetCode 256. 粉刷房子

发布时间 2023-04-03 09:51:36作者: Frodo1124

题目链接

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。
示例 2:
输入: costs = [[7,6,2]]
输出: 2

思路

分析动态规划题目的时候只需要考虑最后一个阶段,因为所有的阶段转化都是相同的,考虑最后一个阶段容易发现规律

表示状态

本题与常规题目不同的一点:本题需要记录三种情况下的花费,因为你不知道每个房子最终会被刷成什么颜色。什么意思呢?举个栗子:

  • 第 n 个房子刷成了红色,那么第 n-1 个房子就要刷成蓝色或绿色,此时需要存储第 n 个房子刷成红色情况下的花费
  • 第 n 个房子刷成了蓝色,那么第 n-1 个房子就要刷成红色或绿色,此时需要存储第 n 个房子刷成蓝色情况下的花费
  • 第 n 个房子刷成了绿色,那么第 n-1 个房子就要刷成蓝色或红色,此时需要存储第 n 个房子刷成绿色情况下的花费

既然我们要存储三份信息,索性就直接定义三个数组 redDPblueDPgreenDP 分别存储第 i 个房子刷成某种颜色情况下的花费。

找状态转移方程

还是从最终阶段出发,

  • 第 n 个房子是红色,说明第 n-1 个房子是蓝色或绿色,此时到第 n 个房子的总花费为 \(min(blueDP[n-1], greenDP[n-1]) + cost[n][0]\)
  • 第 n 个房子是蓝色,说明第 n-1 个房子是红色或绿色,此时到第 n 个房子的总花费为 \(min(redDP[n-1], greenDP[n-1]) + cost[n][1]\)
  • 第 n 个房子是绿色,说明第 n-1 个房子是蓝色或红色,此时到第 n 个房子的总花费为 \(min(blueDP[n-1], redDP[n-1]) + cost[n][2]\)

边界处理

很容易知道

redDP[0] = costs[0][0];
blueDP[0] = costs[0][1];
greenDP[0] = costs[0][2];

空间优化

因为每个数组的第 i 项只与第 i-1 项有关,所以只需要三个单变量分别表示第 i-1 项,循环滚动更新就行。

代码

dp数组版

class Solution {
    public int minCost(int[][] costs) {
        if(costs.length == 0){
            return 0;
        }

        int n = costs.length;
        // 第 i 个房子刷成红色情况下的最小花费
        int[] redDP = new int[n];
        // 第 i 个房子刷成蓝色情况下的最小花费
        int[] blueDP = new int[n];
        // 第 i 个房子刷成绿色情况下的最小花费
        int[] greenDP = new int[n];

        redDP[0] = costs[0][0];
        blueDP[0] = costs[0][1];
        greenDP[0] = costs[0][2];

        for(int i = 1; i < n; i++){
            redDP[i] = Math.min(blueDP[i - 1], greenDP[i - 1]) + costs[i][0];
            blueDP[i] = Math.min(redDP[i - 1], greenDP[i - 1]) + costs[i][1];
            greenDP[i] = Math.min(blueDP[i - 1], redDP[i - 1]) + costs[i][2];
        }

        return Math.min(Math.min(redDP[n - 1], blueDP[n - 1]), greenDP[n - 1]);
    }
}

空间优化版

class Solution {
    public int minCost(int[][] costs) {
        if(costs.length == 0){
            return 0;
        }

        int n = costs.length;
        int redCost = costs[0][0];
        int blueCost = costs[0][1];
        int greenCost = costs[0][2];

        for(int i = 1; i < n; i++){
            int newRedCost = Math.min(blueCost, greenCost) + costs[i][0];
            int newBlueCost = Math.min(redCost, greenCost) + costs[i][1];
            int newGreenCost = Math.min(redCost, blueCost) + costs[i][2];

            redCost = newRedCost;
            blueCost = newBlueCost;
            greenCost = newGreenCost;
        }

        return Math.min(Math.min(redCost, blueCost), greenCost);
    }
}