265. 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.

Example:

Input: [[1,5,3],[2,9,4]]
Output: 5
Explanation: Paint house 0 into color 0, paint house 1 into color 2. Minimum cost: 1 + 4 = 5;
Or paint house 0 into color 2, paint house 1 into color 0. Minimum cost: 3 + 2 = 5.

Follow up:

  1. Could you solve it in O(nk) runtime?

方法1: dynamic programming

思路:

正常的dynamic programming思路是填入n * k大小的matrix,而每一个dp[i][j]暴力解的话都需要遍历之前一个房子的O(k)项,这就造成了O(nk^2)的复杂度。follow up中要求O(nk)要怎么做到呢?实际上我们只需要前一轮至多两个最小值:如果当第 j 个房子和min1一样,那只能选择min2,如果不一样,可以直接选min1。这里的min1和min2应该是index而不是cost,因为我们需要同时知道取到最小cost的上一轮颜色是什么才能选择min1还是min2。

class Solution {
public:
    int minCostII(vector<vector<int>>& costs) {
        if (costs.empty() || costs[0].empty()) return 0;
        int n = costs.size(), k = costs[0].size();
        // vector<vector<int>> dp(n, vector<int>(k, 0));
        // 这里由于每个dp项一定要累加进将当前房子i 染成颜色j的cost,所以可以考虑直接在costs的基础上累加
        vector<vector<int>> dp = costs;
        int min1 = -1, min2 = -1;
       
        for (int i = 0; i < n; i++) {
            // 先记录上一轮的min1,min2
            int last1 = min1, last2 = min2;
            min1 = -1; min2 = -1;
            
            for (int j = 0; j < k; j++) {
                if (j != last1) dp[i][j] += last1 < 0 ? 0 : dp[i - 1][last1];
                else dp[i][j] += last2 < 0 ? 0: dp[i - 1][last2];
                
                // 这里是running update min1和min2,因此都是和同一轮的dp[i][min1]/dp[i][min2]比较
                // 出现新的min1
                if (min1 < 0 || dp[i][j] < dp[i][min1]) {
                    min2 = min1; min1 = j;
                }
                // 出现新的min2
                else if (min2 < 0 || dp[i][j] < dp[i][min2]) {
                    min2 = j;
                }
            }
        }
        return dp.back()[min1];
    }
};

方法2: dynamic programming,1d

discussion:https://leetcode.com/problems/paint-house-ii/discuss/69541/C%2B%2B-DP-time-O(nk)-space-O(k)

思路:

int minCostII(vector<vector<int>>& costs) {
    int n = costs.size();
    if(n==0) return 0;
    int k = costs[0].size();
    if(k==1) return costs[0][0];

    vector<int> dp(k, 0);
    int min1, min2;

    for(int i=0; i<n; ++i){
        int min1_old = (i==0)?0:min1;
        int min2_old = (i==0)?0:min2;
        min1 = INT_MAX;
        min2 = INT_MAX;
        for(int j=0; j<k; ++j){
            if(dp[j]!=min1_old || min1_old==min2_old){
                dp[j] = min1_old + costs[i][j];
            }else{//min1_old occurred when painting house i-1 with color j, so it cannot be added to dp[j]
                dp[j] = min2_old + costs[i][j];
            }

            if(min1<=dp[j]){
                min2 = min(min2, dp[j]);
            }else{
                min2 = min1;
                min1 = dp[j];
            }
        }
    }

    return min1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值