目录

1. 粉刷房子

1.1 题目解析

1.2 解法

1.3 代码实现


1. 粉刷房子

https://leetcode.cn/problems/JEj789/

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

1.1 题目解析

题目本质
这是一个带约束条件的最优化问题——在"相邻房子颜色不同"的约束下,求最小成本。

常规解法
枚举所有可能的涂色方案(第一个房子3种选择,第二个房子2种选择...),计算每种方案的总成本,取最小值。

问题分析
对于 n 个房子,方案数约为 3×2^(n-1),当 n=100 时会超时。需要避免重复计算——比如"前3个房子怎么涂"这个子问题会在很多方案中重复出现。

思路转折
要想高效 → 必须利用动态规划消除重复计算 → 定义状态"粉刷到第 i 个房子且第 i 个房子用颜色 j 的最小成本" → 每次决策只需要看上一个房子的另外两种颜色即可。
关键是认识到:当前房子的最优解只依赖于上一个房子的状态,不需要知道更早的具体颜色选择。

1.2 解法

算法思想:动态规划。定义 dp[i][j] 表示粉刷到第 i 个房子且第 i 个房子用颜色 j 的最小成本。

递推公式:

dp[i][0] = min(dp[i-1][1], dp[i-1][2]) + costs[i][0]
dp[i][1] = min(dp[i-1][0], dp[i-1][2]) + costs[i][1]
dp[i][2] = min(dp[i-1][0], dp[i-1][1]) + costs[i][2]

i)创建 dp[m+1][3] 数组,dp[0][j] 初始为 0(表示还没开始粉刷)

ii)从第 1 个房子开始遍历到第 m 个房子

iii)对于每个房子,计算使用三种颜色的最小成本(从上一个房子的另外两种颜色中选最小的)

iv)返回 min(dp[m][0], dp[m][1], dp[m][2])

易错点

  • 索引对应关系:dp[i] 对应 costs[i-1],因为 dp 数组从 1 开始(第 1 个房子),而 costs 从 0 开始(第 0 号房子)

  • 状态更新顺序:每个房子的三种颜色要在同一轮循环中计算,确保都基于上一行的完整数据,而不是当前行部分更新的值

  • 依赖关系理解:dp[i][0] 依赖 dp[i-1][1] 和 dp[i-1][2](不能用同色),注意这里的 i-1 是上一行,不会和当前行的 dp[i][1]、dp[i][2] 冲突

1.3 代码实现

class Solution {
    int m;
    public int minCost(int[][] costs) {
        m = costs.length;
        int[][] dp = new int[m+1][3];

        // 从第1个房子开始遍历到第m个房子
        for (int i = 1; i <= m; i++) {
            // 当前房子涂颜色0,从上一个房子的颜色1或2中选最小的
            dp[i][0] = Math.min(dp[i-1][1], dp[i-1][2]) + costs[i-1][0];
            dp[i][1] = Math.min(dp[i-1][0], dp[i-1][2]) + costs[i-1][1];
            dp[i][2] = Math.min(dp[i-1][0], dp[i-1][1]) + costs[i-1][2];
        }

        // 返回最后一个房子三种颜色中的最小成本
        return Math.min(dp[m][0], Math.min(dp[m][1], dp[m][2]));  
    }
}

复杂度分析

  • 时间复杂度:O(n),遍历 n 个房子,每个房子做常数次比较运算。

  • 空间复杂度:O(n),使用了 (n+1)×3 的 dp 数组。可优化至 O(1)(只保留上一行的状态)。

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐