1.题意
一个长度为 n 的字符串 s,其中仅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符。
如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。
现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?
如果 s 已经平衡则输出0。
2.样例
Input
一行字符表示给定的字符串s
Output
一个整数表示答案
Sample Input1
QWER
Sample Output1
0
Sample Input2
QQWE
Sample Output2
1
Sample Input3
QQQW
Sample Output3
2
Sample Input4
QQQQ
Sample Output4
3
3.解题思路
- 由数据范围知暴力做法复杂度为O(n^2)不能接受
- 因为所求解答案为一个连续区间且区间左右端点移动有明确的方向,所以用尺取法,当前[l,r]满足要求则l++,否则r++
- 先通过替换使4类字符数量一致,再判断空闲位置是否>=0且为4的倍数
4.总结
- 尺取法适用于所求解答案为一个连续区间且区间左右端点移动有明确的方向
- 注意必须是[l,r]不满足要求才r++,l++直到不满足要求,每l++一次同样要判定是否符合
- 若定义的l=1,则在l ++前补齐之前的sum_i时判断的是str[l-1],从左边减一开始补,同样在r++,sum_i–时如果r++在前则在循环之前要先将str[0]对应的sum_i–,r++在后则不需要。
5.AC代码
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
int sum1=0,sum2=0,sum3=0,sum4=0,count=0;
string str;
cin>>str;
for(int i=0;i<str.size();i++)
{
if(str[i]=='Q') sum1++;
if(str[i]=='W') sum2++;
if(str[i]=='E') sum3++;
if(str[i]=='R') sum4++;
}
int ave=str.size();
if(sum1==sum2&&sum2==sum3&&sum3==sum4)
{
cout<<0<<endl;
return 0;
}
int ans=ave+1,l=1,r=0,total=0,free=0;
while(r<=ave)
{
if(l<=r&&free>=0&&free%4==0)
{
ans=min(ans,total);
if(str[l-1]=='Q') sum1++;
if(str[l-1]=='W') sum2++;
if(str[l-1]=='E') sum3++;
if(str[l-1]=='R') sum4++;
l++;
}
else{
if(str[r]=='Q') sum1--;
if(str[r]=='W') sum2--;
if(str[r]=='E') sum3--;
if(str[r]=='R') sum4--;
r++;
}
total=r-l+1;
free=total;
int maxx=max(max(sum1,sum2),max(sum3,sum4));
free-=(maxx-sum1)+(maxx-sum2)+(maxx-sum3)+(maxx-sum4);
}
cout<<ans<<endl;
return 0;
}