题面
一个长度为 n 的字符串 s,其中仅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符。
如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。
现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?
如果 s 已经平衡则输出0。
Input
一行字符表示给定的字符串s(length<=105且 mod 4=0)。
Output
一个整数表示答案
Examples
Input
QWER
Output
0
Input
QQWE
Output
1
Input
QQQW
Output
2
Input
QQQQ
Output
3
思路
有一个明显的贪心,不管元素连不连续,要尽可能替换更少的元素,那么我们要找到不得不替换的元素,即只要把多于平均数的元素,替换成缺少的元素就可以。可以证明替换其他元素是无意义的。所以我们先求出需要替换的元素和个数。
对于一个搜素范围[l,r],求出其中每种可替换元素的数目,若大于等于相应种类的所需元素。说明搜索范围比较大,右边界右移。否则,左边界右移。
为了快速求解每个区间里元素数目,采用前缀和优化。可以获得均摊
O
(
1
)
O(1)
O(1)的复杂度
代码
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<map>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define mem(a,s) memset(a,s,sizeof(a))
map<char,int> m;
int n;
int a[100010];
int tt[4];
int sum[100010][4];
int main(){
// freopen("1.txt","r",stdin);
m['Q']=0;m['W']=1;
m['E']=2;m['R']=3;
string s;
mem(sum,0);mem(tt,0);
cin>>s;
rep(i,0,s.size()-1){//读入,QWER求数量
a[++n]=m[s[i]];
tt[a[n]]++;
}
int avg=n/4;
rep(i,0,3)//求与目标元素的差
tt[i]-=avg;
rep(x,0,3)//求前缀和
rep(i,1,n){
sum[i][x]=sum[i-1][x];
if(a[i]==x)
sum[i][x]++;
}
int l=1,r=0;//特殊情况ans=0
int ans=1e5;
while(l<=n&&r<=n){
bool pd=true;
rep(i,0,3)//区间内QWER元素要大于等于需要修改的元素
if((sum[r][i]-sum[l-1][i])<tt[i]){
pd=false;break;
}
if(pd){//满足
int d=r-l+1;
ans=min(ans,d);
l++;
}else r++;
}
cout<<ans;
return 0;
}