题意:
有一串字符,长度为n(n为4的倍数),其中仅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符。如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。可将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,求替换字符串的最小长度。
input:
一串字符。
output:
字符串的最小长度,如果本来就是平衡的,则输出0。
思路:
利用尺取法可以得到,首先可知,替换的字符串越长其越能成功。即有尺取的区间l和r。如果当前的区间不能替换成功,则说明区间小了,则r++,否则区间能成功,可尝试更小的区间l++。 接下来即为能否成功的判定条件,首先需要在这个而区间外的各个字符的个数。不妨设为sum[0~3]。因为替换后字符的数量只会增加,故要想平衡则向字符数最大的一个(设为max),则需要替换的字符数量为 total=4max-(sum[1~3])。此时可替换的为free=r-l+1。若free>total,且替换后free的值仍为4的倍数,则为可以成功,否则不成功。每次符合条件后,可判定是否为当前最短的,再选择是否覆盖。最后输出最短的长度即可。注意在移动区间的时候,要更新sum的值,即有新的字符进来,有旧的字符出去。
总结:
一开始准备用getchar读字符,但不知道最后终止的条件,然后用的string读,同时可以得到字符串的长度。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
using namespace std;
int sum[4];
int num=100000; //所需要替换的字母数量
int f(char c){
if(c=='Q') return 0;
if(c=='W') return 1;
if(c=='E') return 2;
if(c=='R') return 3;
}
int fmax(){
return max(max(sum[0],sum[1]),max(sum[2],sum[3]));
}
int main(){
string c;
cin>>c;
int len=c.length();
for(int i=0; i<len;i++){
int j=f(c[i]);
sum[j]++;
}
int j=f(c[0]);
sum[j]--;
int l=0,r=0; //左右端点
int Max=fmax(); //字符数最多的
int total=r-l+1; //可修改的
int free=total-(4*Max-sum[0]-sum[1]-sum[2]-sum[3]); //剩余修可供修改的
while(1){
int j=0;
if(free>=0 && (free%4)==0 ){ //符合要求
if(total<num) num=total;
j=f(c[l]);
l++;
sum[j]++;
}else{ //不符合要求
if(r<len-1){
r++;
}else{
break;
}
j=f(c[r]);
sum[j]--;
}
Max=fmax();
total=r-l+1;
free=total-(4*Max-sum[0]-sum[1]-sum[2]-sum[3]);
}
if(num==100000) num=0;
cout<<num<<endl;
return 0;
}