题目链接:https://leetcode-cn.com/problems/UlBDOe/
-
这道题拿到手上,直接懵了,感觉dp、贪心什么的都不对,因为题目好像不存在什么序的关系。
-
但是,仔细想想,最后一个叶子必然为红色段(如果叶子本身为 y y y,那么肯定要改成 r r r),那么到最后一片叶子前面总共修改了几次,那么就看前 n − 1 n-1 n−1片叶子总共修改了几次(此时似乎出现了子结构),但是第 n − 1 n-1 n−1片叶子可以是处于阶段2(即 y y y叶子段)、也可以是处于阶段3(即 r r r叶子段)(此时似乎出现了决策(状态转移))。
-
状态定义:定义成三维
1、 d p ( i , 0 ) dp(i,0) dp(i,0)表示第 i i i片叶子处于阶段1( r r r叶子段)时,前i片最少需要修改的个数。
2、 d p ( i , 1 ) dp(i,1) dp(i,1)表示第 i i i片叶子处于阶段2( y y y叶子段)时,前i片最少需要修改的个数。
3、 d p ( i , 2 ) dp(i,2) dp(i,2)表示第 i i i片叶子处于阶段3( r r r叶子段)时,前i片最少需要修改的个数。 -
状态转移:根据目前所处的阶段和本身的叶子颜色进行转移:
1、 d p ( i , 0 ) = d p ( i − 1 , 0 ) + ( l e a [ i ] = = ′ r ′ ? 0 : 1 ) dp(i,0)=dp(i-1,0)+(lea[i]=='r'\ ?\ 0:\ 1) dp(i,0)=dp(i−1,0)+(lea[i]==′r′ ? 0: 1)
2、 d p ( i , 1 ) = m i n ( d p ( i − 1 , 0 ) , d p ( i − 1 , 1 ) ) + ( l e a [ i ] = = ′ r ′ ? 1 : 0 ) dp(i,1)=min(dp(i-1,0),dp(i-1,1))+(lea[i]=='r'\ ?\ 1:\ 0) dp(i,1)=min(dp(i−1,0),dp(i−1,1))+(lea[i]==′r′ ? 1: 0)(处于阶段2的叶子,前面的第 i − 1 i-1 i−1片可以是红叶、也可以是黄叶)
3、 d p ( i , 2 ) = m i n ( d p ( i − 1 , 1 ) , d p ( i − 1 , 2 ) ) + ( l e a [ i ] = = ′ r ′ ? 0 : 1 ) dp(i,2)=min(dp(i-1,1),dp(i-1,2))+(lea[i]=='r'\ ?\ 0:\ 1) dp(i,2)=min(dp(i−1,1),dp(i−1,2))+(lea[i]==′r′ ? 0: 1)(处于阶段3的叶子,前面的第 i − 1 i-1 i−1片可以是黄叶、也可以是红叶) -
初始化(这里至关重要):
1、 d p ( 0 , 0 ) dp(0,0) dp(0,0)必须是红叶,所以要根据第一片叶子的颜色进行初始化。
2、因为第一片叶子必须是红叶,所以 d p ( 1 , 1 ) dp(1,1) dp(1,1)必须根据 d p ( 0 , 0 ) dp(0,0) dp(0,0)初始化,即使 l e a [ 1 ] lea[1] lea[1]为黄色, l e a [ 0 ] lea[0] lea[0]为黄色的话, d p ( 1 , 1 ) dp(1,1) dp(1,1)也不可能为0。
3、同样的, d p ( 2 , 2 ) dp(2,2) dp(2,2)要根据 d p ( 1 , 1 ) dp(1,1) dp(1,1)进行初始化。 -
递推:
1、阶段1只需要从第二片叶子开始推,因为第一片叶子肯定是红色。
2、阶段2只需要从第三片叶子开始推,因为第二片叶子为黄色的时候,已经被初始化了,这样后面递推的时候才不会出错。
3、阶段3同样只需要从第四片叶子开始推。
const int MAXN = 1e5 + 5;
int dp[MAXN][3];
class Solution {
public:
// r y r
int minimumOperations(string leaves) {
memset(dp, 0, sizeof(dp));
int n = leaves.length();
if (leaves[0] == 'r') dp[0][0] = 0;
else dp[0][0] = 1;
for (int i = 1; i < n; i++){
if (leaves[i] == 'r') dp[i][0] = dp[i - 1][0];
else dp[i][0] = dp[i - 1][0] + 1;
}
if (leaves[1] == 'y') dp[1][1] = dp[0][0];
else dp[1][1] = dp[0][0] + 1;
for (int i = 2; i < n; i++){
if (leaves[i] == 'r')
dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]) + 1;
else dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]);
}
if (leaves[2] == 'r') dp[2][2] = dp[1][1];
else dp[2][2] = dp[1][1] + 1;
for (int i = 3; i < n; i++){
if (leaves[i] == 'r')
dp[i][2] = min(dp[i - 1][1], dp[i - 1][2]);
else dp[i][2] = min(dp[i - 1][1], dp[i - 1][2]) + 1;
}
// 最后 n - 1 必须是状态 3
return dp[n - 1][2];
}
};