【秋叶收藏集】

传送门

题意

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

posted @ 2020-09-14 11:20  Valk3  阅读(198)  评论(0编辑  收藏  举报