平衡字符串
一个长度为 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扫描二维码关注公众号,回复: 10462081 查看本文章
Input:
QQQQ
Output:
3
我的思路:
这道题要达到的目的,是通过替换字符串中的一段连续字符,来使得‘Q’ 、‘W’、 ‘E’、 'R’这四个字母在字符串中的个数相等,求能达到这个要求的最短连续字符的长度。我用的是尺取法,即设置两个指针,一个左端指针L和一个右端指针R,从最左端的第一个元素开始,计算这个区间外的四个字母个数,若当前区间可以达到将四个字母个数填充相等(即区间外的四个字母个数与其中最大个数的差距,用区间弥补,弥补过后若剩下的空余空间是4的倍数(或0),则满足条件),则将左指针向右移一个单位;否则,右指针向右移动一个单位。最后,统计满足条件的最短长度即可。
我的总结:
对于这种改变一段连续的区间,并求最短距离的问题,尺取法是一个很好的方法,在时间复杂度上要优于二分。
我的代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
string s;
long long ans,sum[4],MAX,tot,fre,L,R;
void su(long long idl,long long idr)
{
for(long long i=0;i<4;i++) sum[i]=0;
for(long long i=0;i<idl;i++)
{
if(int(s[i])==int('Q')) sum[0]++;
if(int(s[i])==int('W')) sum[1]++;
if(int(s[i])==int('E')) sum[2]++;
if(int(s[i])==int('R')) sum[3]++;
}
for(long long i=idr+1;i<s.size();i++)
{
if(int(s[i])==int('Q')) sum[0]++;
if(int(s[i])==int('W')) sum[1]++;
if(int(s[i])==int('E')) sum[2]++;
if(int(s[i])==int('R')) sum[3]++;
}
}
long long jud()
{
L=R=0;
su(L,R);
while(L<s.size()&&R<s.size()&&L<=R)
{
MAX=max(max(sum[0],sum[1]),max(sum[2],sum[3]));
tot=R-L+1;
fre=tot-((MAX-sum[0])+(MAX-sum[1])+(MAX-sum[2])+(MAX-sum[3]));
if(fre>=0&&fre%4==0)
{
ans=min(ans,R-L+1);
if(int(s[L])==int('Q')) sum[0]++;
if(int(s[L])==int('W')) sum[1]++;
if(int(s[L])==int('E')) sum[2]++;
if(int(s[L])==int('R')) sum[3]++;
L++;
}
else
{
R++;
if(int(s[R])==int('Q')) sum[0]--;
if(int(s[R])==int('W')) sum[1]--;
if(int(s[R])==int('E')) sum[2]--;
if(int(s[R])==int('R')) sum[3]--;
}
}
return ans;
}
int main()
{
while(cin>>s)
{
su(0,-1);
if(sum[0]==sum[1]&&sum[1]==sum[2]&&sum[2]==sum[3])
{
printf("0\n");
continue;
}
ans=s.size();
printf("%lld\n",jud());
}
return 0;
}