题目描述
一个长度为 n 的字符串 s,其中仅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符。
如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。
现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?
如果 s 已经平衡则输出0。
Input
一行字符表示给定的字符串s
Output
一个整数表示答案
Examples
Input
QWER
Output
0
Input
QQWE
Output
1
Input
QQQW
Output
2
Input
QQQQ
Output
3
Notes
1<=n<=10^5
n是4的倍数
字符串中仅包含字符 'Q', 'W', 'E' 和 'R'.
解题思路
由于本题所求为一连续区间的长度,并且需要一个双指针来维护这个数组的移动,因此符合尺取法的条件。当区间符合要求时左指针右移,否则右指针右移。而是否符合要求的判断条件是,如果个数最多的元素依然不多于字符串平均值,则说明一定符合要求,否则便不符合要求。在移动之前先初始化左,右指针的位置于第一个元素的位置,并计算出初始化的数组是否已经符合条件,若符合则无需再做判断;若不符合则进入循环判断。
代码
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s;
cin>>s;
char letter[4]={'Q','W','E','R'};
int sum[4]={0};//四种字符个数的数量
int l=0,r=0;//尺取法的左右端点
int n=s.size();
for(int i=0;i<n;i++)
{
if(s[i]=='Q') sum[0]++;
if(s[i]=='W') sum[1]++;
if(s[i]=='E') sum[2]++;
if(s[i]=='R') sum[3]++;
}
if(sum[0]==sum[1]&& sum[0]==sum[2]&& sum[0]==sum[3])
{
cout<<0<<endl;
return 0;
}
for(int i=0;i<4;i++)
if(s[0]==letter[i])
sum[i]--;
int ans=n-1;
while(1<n)
{
int t1=max(sum[0],sum[1]);
int t2=max(sum[2],sum[3]);
int m=max(t1,t2);
int total=r-l+1;
if(m<=n/4)//一种更简单的判断方法,只要最大个数比平均个数少就可以平衡
{
if(total<ans) ans=total;
for(int i=0;i<4;i++)//修改剩下字母的个数
if(s[l]==letter[i])
sum[i]++;
l++;
}
else
{
if(r==n-1) break;
for(int i=0;i<4;i++)//修改剩下字母的个数
if(s[r+1]==letter[i])
sum[i]--;
r++;
}
}
cout<<ans<<endl;
return 0;
}