SDU_week5_C - 平衡字符串(尺取法/蠕虫法)

题目描述

一个长度为 n 的字符串 s,其中仅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符。
如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。
现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?
如果 s 已经平衡则输出0。

Input
一行字符表示给定的字符串s

Output
一个整数表示答案

Examples
Input
QWER
Output
0

Input
QQWE
Output
1

Input
QQQW
Output
2

Input
QQQQ
Output
3

Note
1<=n<=10^5
n是4的倍数
字符串中仅包含字符 ‘Q’, ‘W’, ‘E’ 和 ‘R’.

题目分析

简单来说是给定长度为4x且由四种字母组成的随机字符串,问要改变某一连续段使其每个字母长度都为x,这段长度最短是多少。

我们采用的方法是尺取法,也叫蠕虫法毛毛虫法,即让[L,R]区间像毛毛虫一样向前移动,当前 [L, R] 满足要求,则 L++ ,当前 [L, R] 不满足要求,则 R++ ,同时维护最短的一个ans值(R-L+1)。
思考一个问题, 给定 [L, R],如何判断是否满足要求?方法是记录[L,R]区间外的各个字母数量,然后由:
MAX = max(sum1, sum2, sum3, sum4) //数量最多的字母
TOTAL = R – L + 1 //区间段长度
FREE = TOTAL [(MAX-sum1)+(MAX-sum2)+(MAX-sum3)+(MAX-sum4)] //自由替换字母,需要>=0且为4的倍数
然后通过下面代码维护区间外的sum值以及ans:

        if (FREE >= 0 && FREE % 4 == 0)
        {
            if(TOTAL<ans)
                ans = TOTAL;
            sum[str[l]]++;
            l++;

        }
        else
        {
            r++;
            sum[str[r]]--;
        }

直到一个R越界停止循环。

HIT

后期发现其实已经平衡不用单独处理,答案已经包含了这种情况。

代码

#include <iostream>
#include<map>
#include<algorithm>
using namespace std;

map<char, int> sum;
char str[1000000];

int main()
{
    char c;//每次输入的字符
    int l = 0;
    int r = -1;
    sum['Q'] = 0;
    sum['W'] = 0;
    sum['E'] = 0;
    sum['R'] = 0;
    while ((c=getchar())!='\n')
    {
        str[++r] = c;
        sum[c]++;
    }

    if (sum['Q']== sum['W']&& sum['Q'] == sum['E']&& sum['Q']==sum['R'])
    {//如果 s 已经平衡
        cout << 0;
        return 0;
    }

    int n = r + 1;//字符串长度
    r = 0;//初始化区间长度为1
    sum[str[0]]--;
    int ans=99999999;
    int MAX;//数量最多的字母
    int TOTAL;//区间段长度
    int FREE;//自由替换字母,需要>=0且为4的倍数
    while (true)
    {
        MAX = max(max((max(sum['Q'], sum['W'])), sum['E']), sum['R']);
        TOTAL = r - l + 1;
        FREE = TOTAL - ((MAX - sum['Q']) + (MAX - sum['W']) + (MAX - sum['E']) + (MAX - sum['R']));
        if (FREE >= 0 && FREE % 4 == 0)
        {
            if(TOTAL<ans)
                ans = TOTAL;
            sum[str[l]]++;
            l++;

        }
        else
        {
            r++;
            sum[str[r]]--;
        }

        if (r >= n)//r是从0开始的,为n时已经越界
            break;
    }
    cout << ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值