链接
https://leetcode-cn.com/problems/UlBDOe/
耗时
解题:3 h 15 min
题解:58 min
题意
小扣出去秋游,途中收集了一些红叶和黄叶,他利用这些叶子初步整理了一份秋叶收藏集 leaves, 字符串 leaves 仅包含小写字符 r 和 y, 其中字符 r 表示一片红叶,字符 y 表示一片黄叶。
出于美观整齐的考虑,小扣想要将收藏集中树叶的排列调整成「红、黄、红」三部分。每部分树叶数量可以不相等,但均需大于等于 1。每次调整操作,小扣可以将一片红叶替换成黄叶或者将一片黄叶替换成红叶。请问小扣最少需要多少次调整操作才能将秋叶收藏集调整完毕。
思路
这是之前 leetcode 一个 CUP 的题,比赛时没做出来,当时想用贪心,后来看答案才想 DP。由于之前看过答案,自己也没有思路,所以这是照答案的思路写的。
三个一维 dp,
dp[0][:] 是字符串的字符的排列调整成「红」一部分,即都换成 r 需要调整多少次;
dp[1][:] 是字符串的字符的排列调整成「红、黄」二部分,即换成 rrrr…yyy 最少需要调整多少次;
dp[2][:] 是字符串的字符的排列调整成「红、黄、红」三部分,即换成 rrrrr…yyy…rrrr 最少需要调整多少次;
dp[0][i] 非常简单,直接看 leaves[i] 是不是 r 就行了;
dp[1][i] 就有两种情况了,…,两种情况取最小
1. 从 dp[0][i-1] 全是 r 的转移过来,变成 rrrr...rrrry
2. 从 上一个状态 dp[1][i-1] 转移过来,变成 rrrr...rrrry..y
dp[2][i] 和 dp[1][i] 差不多,
1. 从 dp[1][i-1] 转移过来,变成 rrrr...rrrry..yr
2. 从 上一个状态 dp[2][i-1] 转移过来,变成 rrrr...rrrryyyy...yyyyr..r
状态转移方程:
{
d
p
[
0
]
[
i
]
=
d
p
[
0
]
[
i
−
1
]
+
1
l
e
a
v
e
s
[
i
]
=
=
′
r
′
d
p
[
1
]
[
i
]
=
m
i
n
(
d
p
[
0
]
[
i
−
1
]
,
d
p
[
1
]
[
i
−
1
]
)
+
1
l
e
a
v
e
s
[
i
]
=
=
′
y
′
d
p
[
2
]
[
i
]
=
m
i
n
(
d
p
[
1
]
[
i
−
1
]
,
d
p
[
2
]
[
i
−
1
]
)
+
1
l
e
a
v
e
s
[
i
]
=
=
′
r
′
\begin{cases} dp[0][i] = dp[0][i-1] + 1^{leaves[i]=='r'} \\ dp[1][i] = min(dp[0][i-1], dp[1][i-1]) + 1^{leaves[i]=='y'} \\ dp[2][i] = min(dp[1][i-1], dp[2][i-1]) + 1^{leaves[i]=='r'} \end{cases}
⎩⎪⎨⎪⎧dp[0][i]=dp[0][i−1]+1leaves[i]==′r′dp[1][i]=min(dp[0][i−1],dp[1][i−1])+1leaves[i]==′y′dp[2][i]=min(dp[1][i−1],dp[2][i−1])+1leaves[i]==′r′
时间复杂度: O ( n ) O(n) O(n)
AC代码
class Solution {
public:
int minimumOperations(string leaves) {
int n = leaves.size();
vector<vector<int>> dp(3, vector<int>(n+1, 0));
dp[0][1] = dp[2][1] = dp[1][1] = (leaves[0]=='r'?0:1);
dp[2][2] = dp[1][2] = dp[1][1] + (leaves[1]=='y'?0:1);
dp[0][2] = dp[0][1] + (leaves[1]=='r'?0:1);
for(int i = 3; i <= n; ++i) {
dp[0][i] = dp[0][i-1] + (leaves[i-1]=='r'?0:1);
dp[1][i] = min(dp[0][i-1], dp[1][i-1]) + (leaves[i-1]=='y'?0:1);
dp[2][i] = min(dp[1][i-1], dp[2][i-1]) + (leaves[i-1]=='r'?0:1);
}
return dp[2][n];
}
};