【秋叶收藏集】

传送门

题意

给出一个字符串,只包括两个字符 '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;
    }
};

原文地址:https://www.cnblogs.com/valk3/p/13665667.html