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:
- 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;
}