程序设计思维Week5-作业
C-平衡字符串
Description
一个长度为 n 的字符串 s,其中仅包含 'Q', 'W', 'E', 'R' 四种字符。
如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。
现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?
如果 s 已经平衡则输出0。
输入一行字符串,输出一个整数代表替换子串的最小长度。
Sample
input:
QWER
output:
0
input:
QQWE
output:
1
input:
QQQW
output:
2
input:
QQQQ
output:
3
Idea
首先对于输入的字符串,先计算它所有QWER各自的和以此判断它本身是否已经平衡,若平衡则不 需要之后的操作,直接输出0。若不平衡,采用区间 [L,R],初始化区间L=0,R=0。对于每个区间进行判断:计算不包含[L,R]这一段时,QWER各自的个数,对这四个和取最大值(这里使用我们实现写好的四个数取最大值的函数),用最大值分别与不包含[L,R]这一段的QWER的个数作差,取和即为需要替换的个数使4类字符数量一致。接下来我们要判断剩余空闲位置是否为4的倍数,用区间中包含的字符个数减去这个和,如果这个结果大于0并且是4的倍数,说明这个区间满足要求可以使整个字符串平衡。如果该区间满足要求,使左边界右移一个单位试图求一个更小的区间,如果不满足要求,则是右边界右移一个单位试图求一个能满足要求的区间。最后对所有满足要求的区间长度依次比较取最小值即所求答案。
Summary
这道题采用尺取法,思路也比较清晰,对于不平衡的字符串,我们试图改变一个连续区间中的几个字符使4类字符的数量达到一致,如果此时区间中未使用过的字符数是4的倍数,那么它们可以完美通过变化使4类字符的数量保持一致。
需要注意的:
①为简化操作,在计算不包含[L,R]这一段的4类字符的数量时,可以利用之前计算的整个字符串的4类字符的数量,遇到一次相应减一。
②初始化ans,置其为尽可能大的数(INT_MAX),保证其最终能获得正确的最小值。
Codes
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
using namespace std;
string str;
int n;
int L = 0, R = 0;
int q = 0, w = 0, e = 0, r = 0;
int ans = INT_MAX;
int max(int a, int b, int c, int d) {
int t[] = { a,b,c,d };
int res = t[0];
for (int i = 1; i <= 3; i++) {
if (res < t[i])res = t[i];
}
return res;
}
int main()
{
cin.sync_with_stdio(false);
cin >> str;
n = str.size();
for (int i = 0; i < n; i++) {
if (str[i] == 'Q')q++;
else if (str[i] == 'W')w++;
else if (str[i] == 'E')e++;
else if (str[i] == 'R')r++;
}
if (q == w&& w == e&& e == r) { printf("0\n"); return 0; }
while (R < n&&L<=R) {
int Q1 = q, W1 = w, E1 = e, R1 = r;
for (int i = L; i < R+1; i++) {
if (str[i] == 'Q')Q1--;
else if(str[i] == 'W')W1--;
else if (str[i] == 'E')E1--;
else if (str[i] == 'R')R1--;
}
int MAX = max(Q1, W1, E1, R1);
int total = R - L + 1;
int free = total - ((MAX - Q1) + (MAX - W1) + (MAX - E1) + (MAX - R1));
if (free >= 0 && free % 4 == 0) {
if(ans>total)ans = total;
if (L == R) { L++; R++; }
else L++;
}
else R++;
}
printf("%d\n", ans);
}