题意
有一个无限长的字符串“RGBRGBRGB……”,现在给你一个长度为n的字符串,字符全由RGB三种大写字母组成,再给出一个整数k,可以修改给出的字符串的任意字符,问最少需要修改几个字符才能找到一个长度为k的子串是无限字符串的子串。
思路
对原字符串的修改有三种情况,分别是开头为R,G,B的三种,即RGBRGB……,GBRGBR……,BRGBRG……,我们开三个前缀和数组记录三种字符为开头的前缀需要修改的字符个数,当 i 大于 k 是,就每次减去sum[i-k],得到 [ i-k,i ] 区间这三种情况需要修改几个字符,记录三种情况的最小值,最后取这三种的最小值即可;
代码
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
char s1[10] = "RGB", s2[10] = "GBR", s3[10] = "BRG", s[200200];
int sum1[200200], sum2[200200], sum3[200200];
int main(){
int t;
scanf("%d", &t);
while(t--){
sum1[0] = 0;
sum2[0] = 0;
sum3[0] = 0;
int n, k, ans1 = inf, ans2 = inf, ans3 = inf;
scanf("%d%d%s", &n, &k, &s);
for(int i = 0; i < n; i++){
if(i != 0){
sum1[i] = sum1[i-1];
sum2[i] = sum2[i-1];
sum3[i] = sum3[i-1];
}
if(s[i] != s1[i%3]){
sum1[i]++;
}
if(s[i] != s2[i%3]){
sum2[i]++;
}
if(s[i] != s3[i%3]){
sum3[i]++;
}
if(i == k - 1){
ans1 = sum1[i];
ans2 = sum2[i];
ans3 = sum3[i];
}
else if(i >= k){
ans1 = min(ans1, sum1[i] - sum1[i - k]);
ans2 = min(ans2, sum2[i] - sum2[i - k]);
ans3 = min(ans3, sum3[i] - sum3[i - k]);
}
}
ans1 = min(ans1, ans2);
ans1 = min(ans1, ans3);
printf("%d\n", ans1);
}
}