【程序设计思维与实践 Week5 作业C】平衡字符串

题目描述:

一个长度为 n 的字符串 s,其中仅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符。
如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。
现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?
如果 s 已经平衡则输出0。
1<=n<=10^5
n是4的倍数
字符串中仅包含字符 ‘Q’, ‘W’, ‘E’ 和 ‘R’。

输入格式:

一行字符表示给定的字符串s

输出格式:

一个整数表示答案

样例:

在这里插入图片描述

思路:

要选中一段字串,使得任意改变字串内容使得整个字符串为平衡字符串,该子串应满足的条件是:首先要拿出字串中的一部分使得整个字串的四种字母个数个数相同,而且剩余部分应满足是4的倍数,这样便可平均分给四种字母。即假设该子串中有m个字母,而子串外其余部分中四种字母的个数分别为a1,a2,a3,a4;取四个数中最大数为Max,则子串中应取出q=Max-a1+Max-a2+Max-a3+Max-a4个字母进行替换来使得四种字母数量相同,而剩余部分m-q个位置必须平均分给四个字母才能使得字符串是平衡的,即m-q必须能整除4。
知道了子串的选取标准之后,接下来的问题就是如何选择满足该标准的子串,若一一挑选则为O(2n)的复杂度,明显不可取。
这里采用尺取得办法,即使用左右两个指针,指向整个字符串,从头开始向尾滑动,类似一个大小可变的滑动窗口,首先左指针指向字符串首,右指针从字符串首向尾滑动,子串每增加一位,则判断是否满足选取标准,若不满足,左指针向尾滑动得到的结果必然也不满足选取标准,故此时应使得右指针向尾滑动,再进行判断,若子串满足要求,右指针向尾滑动得到的结果必然满足条件,但子串必然变长,对结果并没有贡献,则此时应使左指针向尾滑动以缩短字符串长度,对于满足条件的子串长度记录在一个变量当中,不断取最小则为满足题目要求的结果。
但这种方法并不能判断原本就平衡的字符串,会返回1,因此对这种情况应提前进行判断。

代码:

#include <iostream>
#include<map>
#include<string.h>
using namespace std;
const int size=1e5+10;
char str[size];
map<char,int> mp;
int note[4]={0,0,0,0};
int n,l=1,r=0;
bool solve()
{
	int M=note[0];
	for(int i=1;i<4;i++)
		if(note[i]>M)
			M=note[i];
	int t=r-l+1;
	int temp=t-(M-note[0])-(M-note[1])-(M-note[2])-(M-note[3]);
	if(temp>=0&&temp%4==0)
		return true;
	else
		return false;
}
int main(int argc, char** argv) {
	mp['Q']=0;mp['W']=1;mp['E']=2;mp['R']=3;
	int n=1;
	scanf("%s",str+1);
	n=strlen(str+1);
	for(int i=1;i<=n;i++)
		note[mp[str[i]]]++; 
	int ans=size;
	if(note[0]==note[1]&&note[1]==note[2]&&note[2]==note[3])
		ans=0;
	else
	{
		while(r<=n)
		{
			while(l<=r&&solve())
			{
				ans=min(ans,r-l+1);
				note[mp[str[l]]]++;
				l++;
			}
			r++;note[mp[str[r]]]--;
		}
	}	
	printf("%d\n",ans);
	return 0;
}
发布了24 篇原创文章 · 获赞 8 · 访问量 527

猜你喜欢

转载自blog.csdn.net/weixin_44034698/article/details/104993791