主要思路:
尺取法的两个应用特征:寻找序列中满足要求的连续区间、有一定的方向性
显然本题满足这两个条件:要求替换一段连续的区域,需要从左向右地检查每个子区间,于是可以应用尺取法。
值得注意的是,进行了字符替换后,我们不能减少字符的数量,于是我们需要记录除掉当前区间剩余的部分中各个字符的数量(在本题有四个字符,分别记为sum1、sum2、sum3、sum4),若是有大于n/4的字符,那么这个区间显然是不合法的;也就是说,区间外与平衡字符串的差距是可以通过区间内的字符变动来弥补的,并且弥补后剩下的字符也必须符合平衡字符串的要求,这两点要求缺一不可
遇到满足条件的区间便立即更新答案
注意
需要将已经平衡了的字符串特判
C - 平衡字符串
一个长度为 n 的字符串 s,其中仅包含 'Q', 'W', 'E', 'R' 四种字符。
如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。
现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,
使其变为一个平衡字符串,问替换子串的最小长度?
如果 s 已经平衡则输出0。
Input
一行字符表示给定的字符串s
Output
一个整数表示答案
Sample Input
QQQW
Sample Output
2
A Possible Solution
#include<stdio.h>
const int N=1e5+5;
char s[N],letter[4]={'Q','W','E','R'};
int sum[4]={0},n=0;
//0 1 2 3 --- Q W E R
int main(){
scanf("%s",s);
for(int i=0;s[i]!='\0';i++){
n++;
if(s[i]=='Q')sum[0]++;
else if(s[i]=='W')sum[1]++;
else if(s[i]=='E')sum[2]++;
else if(s[i]=='R')sum[3]++;
}
if(sum[0]==sum[1] && sum[1]==sum[2] && sum[2]==sum[3]){
printf("0\n");
return 0;
}
int l=0,r=0,ans=n+1;
int LRsum[4]={0};
if(s[0]=='Q')LRsum[0]++;
else if(s[0]=='W')LRsum[1]++;
else if(s[0]=='E')LRsum[2]++;
else if(s[0]=='R')LRsum[3]++;
while(r<n){
int maxx=(sum[0]-LRsum[0])>(sum[1]-LRsum[1])?(sum[0]-LRsum[0]):(sum[1]-LRsum[1]);
maxx=maxx>(sum[2]-LRsum[2])?maxx:(sum[2]-LRsum[2]);
maxx=maxx>(sum[3]-LRsum[3])?maxx:(sum[3]-LRsum[3]);
int total=r-l+1,left;
left=total-((maxx-sum[0]+LRsum[0])+(maxx-sum[1]+LRsum[1])+(maxx-sum[2]+LRsum[2])+(maxx-sum[3]+LRsum[3]));
if(left>=0 && left%4==0){
ans=ans<total?ans:total;
l++;
if(s[l-1]=='Q')LRsum[0]--;
else if(s[l-1]=='W')LRsum[1]--;
else if(s[l-1]=='E')LRsum[2]--;
else if(s[l-1]=='R')LRsum[3]--;
if(l==r+1){
r++;//printf("r++ l++\n");
if(s[r]=='Q')LRsum[0]++;
else if(s[r]=='W')LRsum[1]++;
else if(s[r]=='E')LRsum[2]++;
else if(s[r]=='R')LRsum[3]++;
}//else printf("l++\n");
}
else{
r++;//printf("r++\n");
if(s[r]=='Q')LRsum[0]++;
if(s[r]=='W')LRsum[1]++;
if(s[r]=='E')LRsum[2]++;
if(s[r]=='R')LRsum[3]++;
}
}
printf("%d\n",ans);
return 0;
}