传送门
题意
给出一个字符串,只包括两个字符 'r' , 'y',现在可以把 'y' 变成 'r' ,把 'r' 变成 'y',问最少需要多少次,才能把这个字符串变成 'r...y...r...'模式。
思路
一般这种题目我都是通过枚举端点解决。
字符串下标从 1 开始,设两个分段点分别为 (p_1),(p_2)。
那么 区间([1,p_1]) 应该全部变为 ('r'),区间([p_1+1,p_2]) 应该变成 ('y'),区间([p_2+1,len])应该变成 ('r')。
我们先枚举 (p_1) 的位置,再枚举 (p_2) 的位置,得到 (p_2) 为任意值时使得区间 ([p_1+1,len])合法的操作次数。
比如 (yyyrryy)
当 (p_1) 为 1 时,(p_2) 分别为 2,3,4,5,6时,使得区间 ([p_1+1,len])合法的操作次数分别为:
3 2 3 4 3
这时我们来看当 (p_1) 的位置往后递推一个时相应的合法操作次数:
2 3 4 3 向后推了一个y
3 4 3 向后推了一个y
3 2 向后推了一个r
1 向后退了一个r
我们可以发现当往后推的这一个字符为 ('y') 时,操作次数不会发生变化,但是如果向后推的是 ('r'),那么整体会 -1。即:对于每一个 (p_2) ,(p_1+1) 也就意味着 ([p_1+1,p_2]) 这一段少一个字符,如果少了一个 ('r') :区间([p_1+1,p_2])操作次数就会减少,否则不变。而 ([p_2+1,len]) 的操作次数没有发生变化。
首先当 (p_1 ==1) 时,可以求出此时所有 (p_2) 的操作次数,因为这些操作次数只会同时改变。
所以我们可以在 (p_1==1) 的时候就求出所有 (p_1) 的最佳位置。
对于任意一个 (p_1) 其答案为:
[1,p1]的'y'个数 + p1=1时求出的该位置p2的最佳位置的操作次数 - [2,p1]'r'的数量
代码
class Solution {
public:
int minimumOperations(string leaves)
{
int N = 1e5 + 10;
int inf = 0x3f3f3f3f;
int prer[N], prey[N], minn[N],ans[N];
int len = leaves.size();
leaves = "1" + leaves;
for (int i = 1; i <= len; i++) {
prer[i] = prer[i - 1] + (leaves[i] == 'r');
prey[i] = prey[i - 1] + (leaves[i] == 'y');
}
minn[len] = inf;
for (int i = len - 1; i>1; i--) {
ans[i] = prer[i] - prer[1] + prey[len] - prey[i];//求出当p1为1时,p2为i时,使得区间[p1+1,len]合法时的次数
minn[i] = min(ans[i], minn[i + 1]);//求出当p1为i时,使得区间[p1+1,len]合法的最少的操作次数(需减去[2,i]出现过的'r'的数量)
}
int rel = inf;
for (int i = 1; i < len - 1; i++) {//枚举p1
int now = prey[i] + minn[i + 1] - (prer[i] - prer[1]);
rel = min(rel, now);
}
return rel;
}
};