题目描述:
一个长度为 n 的字符串 s,其中仅包含 'Q', 'W', 'E', 'R' 四种字符。
如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。
现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?
如果 s 已经平衡则输出0。
Input:
一行字符表示给定的字符串s
Output:
一个整数表示答案
思路:
输入后用s1 s2 s3 s4分别统计四个字母的个数。如果已经有s1==s2==s3==s4,直接输出0即可。
在下面的算法中,s1s2s3s4分别表示区间l r之外的四个字母的个数。
尺取法:首先另l=r=0(字符串从位置0开始),s1s2s3s4更新,为maxx=max(s1,s2,s3,s4),total=r-l+1(总的空位),free=total-(maxx-s1)-(maxx-s2)-(maxx-s3)-(maxx-s4).(free为将四个字母全部平衡后还剩下的空位)。如果该空位为0或是4的倍数,则该区间是合法的,此时l++,更新s1s2s3s4。如果不满足上述条件,则认为区间不合法,r++,同时更新s1s2s3s4。
对于尺取法,需要满足:1.区间是连续的 2.区间的左右端点有明确的移动方向。
#include<iostream>
#include<cstring>
using namespace std;
int l=0,r=0,n,ans=1000010,s1,s2,s3,s4;
string s;
int main()
{
cin>>s;
n=s.length();
for(int i=0;i<n;i++)
{
if(s[i]=='Q')
s1++;
if(s[i]=='W')
s2++;
if(s[i]=='E')
s3++;
if(s[i]=='R')
s4++;
}
if(s1==s2&&s2==s3&&s3==s4)
{
cout<<0;
return 0;
}
if(s[0]=='Q') s1--;
if(s[0]=='W') s2--;
if(s[0]=='E') s3--;
if(s[0]=='R') s4--;
while(1)
{
int maxx=max(max(s1,s2),max(s3,s4)),total=r-l+1,free;
free=total-(maxx-s1)-(maxx-s2)-(maxx-s3)-(maxx-s4);
if((free>0&&free%4==0)||free==0)//ok
{
ans=min(ans,total);
if(s[l]=='Q') s1++;
if(s[l]=='W') s2++;
if(s[l]=='E') s3++;
if(s[l]=='R') s4++;
l++;
}
else//no
{
if(r+1<n) r++;
else break;
if(s[r]=='Q') s1--;
if(s[r]=='W') s2--;
if(s[r]=='E') s3--;
if(s[r]=='R') s4--;
}
}
cout<<ans;
return 0;
}