问题描述
一个长度为 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
Note
1<=n<=10^5
n是4的倍数
字符串中仅包含字符 ‘Q’, ‘W’, ‘E’ 和 ‘R’.
问题分析
尺取法
尺取法,又称双指针法,是数组上的一种常见操作 ,在遍历数组过程中,用两个相同方向进行扫描。
经典应用:寻找满足某个要求的最小区间Q
设置两个指针l,r,分别代表Q的左右边界。若当前区间不满足要求,则让r++,区间增大,寻找符合要求的区间。若当前区间满足要求,则让l++,区间减小,以寻找新的区间。
每次找到符合要求的区间加以记录,以便得到最小区间。
解题思路
题目要求找到一段连续区间,而且移动方向显然是明确的,因此可以使用尺取法。
区间符合要求的条件为:四种字符在字符串中出现次数均为 n/4
如何判断是否满足条件
假设现在选中的区间为 [l, r] 。首先我们计算出除此区间以外的四类字符数量sum1,sum2, sum3,sum4 。最大值记为max。若要符合要求,则在 [l, r] 中填充完四类字符,使得sum1=sum2=sum3=sum4后,[l, r] 中剩余的位置必须为4的倍数,否则,剩余位置替换后,一定有某一类或几类字符比别的少,无法平衡。
注意
每次移动l,r,都要更新区间外的四类字符数量。
找到一个符合要求的区间,要记录下他的长度。如果当前长度更小,更新最小区间长度。
代码实现
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
char s[100050];
int sum1=0, sum2=0, sum3=0, sum4=0;
void judge(int i)
{
if(s[i] == 'Q') sum1--;
else if(s[i] == 'W') sum2--;
else if(s[i] == 'E') sum3--;
else if(s[i] == 'R') sum4--;
}
void judge2(int i)
{
if(s[i] == 'Q') sum1++;
else if(s[i] == 'W') sum2++;
else if(s[i] == 'E') sum3++;
else if(s[i] == 'R') sum4++;
}
int main()
{
scanf("%s",s);
int i=0;
for(; s[i]!='\0'; i++)
{
judge2(i);
}
if(sum1 == sum2 && sum1 == sum3 && sum1 == sum4 )
printf("0\n");
else
{
int l=0, r=0;
judge(0);
int ans=100050;
for(; r<i;)
{
int maxx = max(max(sum1,sum2),max(sum3,sum4));//最大值
int total = r-l+1;//区间长度
int free = total - (maxx-sum1) - (maxx-sum2) - (maxx - sum3) - (maxx - sum4); //替换字符的剩余长度
if(free >= 0 && free%4 == 0)
{
judge2(l);//更新sum
int temp = r-l+1;//记录当前长度
if(temp < ans) ans = temp;//如果当前长度更小,更新
l++;
}
else
{
r++;
judge(r);//更新sum
}
}
printf("%d\n",ans);
}
}