题目
一个长度为 n 的字符串 s,其中仅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符。
如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。
现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?
如果 s 已经平衡则输出0。
Input
一行字符表示给定的字符串s。
1<=n<=10^5。
n是4的倍数。
字符串中仅包含字符 ‘Q’, ‘W’, ‘E’ 和 ‘R’。
Output
一个整数表示答案。
Sample Input
QQWE
Sample Output
1
思路
由于所求答案为一个连续区间且区间左右端点有明确移动方向,故可以采用尺取法。
当选中区间在范围内,即 R<n&&L<=R 时,循环。
假定已选中区间[L,R]:
- 用 sum1, sum2, sum3, sum4 分别记录不包含区间 [L, R]这一段时,字符 ‘A’, ‘B’, ‘C’, ‘D’ 的个数;
- MAX = max(sum1, sum2, sum3, sum4);
- TOTAL=R–L+1;
- FREE = TOTAL - [(MAX-sum1)+(MAX-sum2)+(MAX-sum3)+(MAX-sum4)]。
则FREE >=0且为4的倍数时,满足要求;否则不满足。
若满足要求,则L++,同时比较此时所得区间长度与之前所得区间长度的最小值,更新ans=min(ans,R-L+1);否则R++。
代码
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
char c[100005];
map<char,int> sum;
int main() {
int n=0;
sum['Q']=0;sum['W']=0;sum['E']=0;sum['R']=0;
while(scanf("%c",&c[n])!=EOF){
sum[c[n]]++;
n++;
}
if(sum['Q']==sum['W']&&sum['W']==sum['E']&&sum['E']==sum['R']){
printf("0");
return 0;
}
int l=0,r=0,ans=n;
sum[c[0]]--;
while(r<n&&l<=r){
int Max=max(max(sum['Q'],sum['W']),max(sum['E'],sum['R']));
int total=r-l+1;
int free=total-(Max-sum['Q'])-(Max-sum['W'])-(Max-sum['E'])-(Max-sum['R']);
if(free>=0&&free%4==0){//符合要求,左边界右移1
ans=min(ans,total);
sum[c[l]]++;
l++;
}
else{//不符合要求,右边界右移1
r++;
if(r<n)
sum[c[r]]--;
}
}
printf("%d",ans);
return 0;
}
总结
第一次用map,感觉十分快乐。
题目链接