题意
一个长度为 n 的字符串 s,其中仅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符。
如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。
现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?
如果 s 已经平衡则输出0。
NOTE
1<=n<=10^5
n是4的倍数
字符串中仅包含字符 ‘Q’, ‘W’, ‘E’ 和 ‘R’.
Input
一行字符表示给定的字符串s
Output
一个整数表示答案
Example
Input Input Input Input
QWER QQWE QQQW QQQQ
Output Output Output Output
0 1 2 3
尺取法总结
概念讲解
尺取法,又称双指针法,是数组上的一种常见操作
样例讲解
-
题意
长度为n的数组,每组数均为正整数,给出正整数s,要求O(n)内求出长度最小的连续区间,使s<=区间和 -
样例
[5 1 3 5 10 7 4 9 2 8], s=15 -
具体流程
①维护双指针L,R,初始L=R=1,sum = a[L]
②当sum>=s时,符合要求,用(R-L+1)更新答案,且L++以寻找最小区间;若L=R,则L++,R++
③当sum<s时,不符合要求,R++,扩展区间以寻找满足条件的区间; -
模拟图
思想
此题使用什么方法?是否可以使用尺取法?
-
满足所求答案为一个连续区间
-
满足区间左右端点移动有明确的方向:当前[L,R]满足要求,则L++;当前[L,R]不满足要求,则R++
因此可以使用尺取法。
具体解法 -
先计算整个字符串中四个字符出现的频率,判断是否相等,若相等,则说明字符串已经平衡,直接输出“0”即可
-
若四个字符出现的频率不相等,则进行[L,R]区间的判断
①用sum11,sum22,sum33,sum44分别记录不同区间[L,R]这一段时,字符’Q’, ‘W’, ‘E’, 'R’的个数
②先通过替换时4类字符数量一致,再判断剩余空闲位置是否为4的倍数
③MAX = max(sum11,sum22,sum33,sum44);
④TOTAL = R - L + 1;
⑤FREE = TOTAL - [(MAX - sum11) + (MAX - sum22) + (MAX - sum33) + (MAX - sum44)]
⑥若FREE >=0且为4的倍数,则满足要求,当前[L,R]满足要求,则L++,以寻求最小区间⑦不满足要求,则R++,继续扩展寻找合适区间
代码
在这里插入代码片#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <algorithm>
using namespace std;
string str;
int L=0,R=0;
int sum1=0,sum2=0,sum3=0,sum4=0;
int main()
{
cin>>str;
int size=str.size();
for(int i=0;i<size;i++)
{
if(str[i]=='Q') sum1++;
if(str[i]=='W') sum2++;
if(str[i]=='E') sum3++;
if(str[i]=='R') sum4++;
}
if(sum1==sum2&&sum2==sum3&&sum3==sum4)
{
cout<<"0"<<endl;
return 0;
}
int ans=size+1;
while(R<=size&&L<=R)
{
int sum11=0,sum22=0,sum33=0,sum44=0;
int sumQ=0,sumW=0,sumE=0,sumR=0;
for(int i=L;i<=R;i++)
{
if(str[i]=='Q') sumQ++;
if(str[i]=='W') sumW++;
if(str[i]=='E') sumE++;
if(str[i]=='R') sumR++;
}
sum11=sum1-sumQ;
sum22=sum2-sumW;
sum33=sum3-sumE;
sum44=sum4-sumR;
int MAX=max(max(sum11,sum22),max(sum33,sum44));
int TOTAL=R-L+1;
int FREE=TOTAL-((MAX-sum11)+(MAX-sum22)+(MAX-sum33)+(MAX-sum44));
if(FREE>=0&&FREE%4==0)//成立
{
ans=min(ans,TOTAL);
L++;
}
else //不成立向右扩展
R++;
//cout<<sum11<<" "<<sum22<<" "<<sum33<<" "<<sum44<<" "<<MAX<<" "<<FREE<<endl;
}
cout<<ans<<endl;
return 0;
}