尺取-平衡字符串(题解)

题意
一个长度为 n 的字符串 s,其中仅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符。
如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。
现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?
如果 s 已经平衡则输出0。
思路:对每个左端点找到合适的右端点确定合适区间,并对最小区间进行及时更新。因为需要平衡字符串,所以在[L,R]之外的Q,W,E,R个数进行计算,首先保证QWER都能达到四者中的最大值,所以[L,R]减去填充的长度后需要>=0&&剩下的%4==0,该过程快速求的一段区间内Q,W,E,R元素个数,可以用前缀和将o(n)降到o(1)
总结
//尺取
//结果是针对于一段连续的区间,而且区间的变化方向是固定的
//每个左端点L能遍历到区间中的所有点
有两个指针l r,判断条件,当符合条件时l++,更新最小区间,当不符合时,r++找到符合区间继续更新最小区间
,这个过程遍历了所以左端点,并对每个左端点对应的小区间进行了遍历,最小区间在该过程中会被更新记录。

先举一个小栗子进行理解:
//求取区间和>=s  的最小区间(部分代码)
int l=1;r=0;
while(r<=n)
{
	while(l<=r&&temp>=s) //满足l++条件 
	{
		
		ans=min(ans,r-l+1);
		temp=temp-a[l];
		l++;
	}
		r++; 
	temp=temp+a[r];

 } 



代码

题解:
//Q W E R    n/4
//找最小区间使得改变和  四者相等 
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int sum1[100010];
int sum2[100010];
int sum3[100010];
int sum4[100010];
char str[100010];
int main()
{
	
    scanf("%s",str+1);// 'Q', 'W', 'E', 'R'
    sum1[0]=0;sum2[0]=0;sum3[0]=0;sum4[0]=0;
	for(int i=1;i<=strlen(str+1);i++)
	{
		if(str[i]=='Q') 
		{
		sum1[i]=sum1[i-1]+1;//前缀和 快速求取一段区间内的某个元素的个数  (快速求取一段区间和) 
		sum2[i]=sum2[i-1];
	    sum3[i]=sum3[i-1];
	   sum4[i]=sum4[i-1];
		}
		if(str[i]=='W') 
		{
			sum2[i]=sum2[i-1]+1;
			sum1[i]=sum1[i-1];
	    sum3[i]=sum3[i-1];
	   sum4[i]=sum4[i-1];
		}
		if(str[i]=='E') 
		{
			sum3[i]=sum3[i-1]+1;
			sum1[i]=sum1[i-1];
	    sum2[i]=sum2[i-1];
	   sum4[i]=sum4[i-1];
			
		}
		if(str[i]=='R') 
		{
		sum4[i]=sum4[i-1]+1;
			sum1[i]=sum1[i-1];
	    sum2[i]=sum2[i-1];
	   sum3[i]=sum3[i-1];	
		}
	}
	if(sum1[strlen(str+1)]==strlen(str+1)/4&&sum2[strlen(str+1)]==strlen(str+1)/4&&sum3[strlen(str+1)]==strlen(str+1)/4&&sum4[strlen(str+1)]==strlen(str+1)/4)
	{
		cout<<0<<endl;exit(0);
	}
	int l=1;int r=0;int ans=100010;int tot;int sm1,sm2,sm3,sm4;
	while(r<=strlen(str+1))
	{  
	   
	  while(l<=r&&tot>=0&&tot%4==0)
		{ 	
	
	    ans=min(ans,r-l+1);//cout<<ans;
			l++;
		sm1=sum1[strlen(str+1)]-(sum1[r]-sum1[l-1]);
		 sm2=sum2[strlen(str+1)]-(sum2[r]-sum2[l-1]);
		 sm3=sum3[strlen(str+1)]-(sum3[r]-sum3[l-1]);
		 sm4=sum4[strlen(str+1)]-(sum4[r]-sum4[l-1]);
		
		 int mmax=max(max(sm1,sm2),max(sm3,sm4));
		 tot=r-l+1;	tot=tot-((mmax-sm1)+(mmax-sm2)+(mmax-sm3)+(mmax-sm4));
	
		}  
		 r++;
		 sm1=sum1[strlen(str+1)]-(sum1[r]-sum1[l-1]);
		 sm2=sum2[strlen(str+1)]-(sum2[r]-sum2[l-1]);
		 sm3=sum3[strlen(str+1)]-(sum3[r]-sum3[l-1]);
		 sm4=sum4[strlen(str+1)]-(sum4[r]-sum4[l-1]);
		 
		 int mmax=max(max(sm1,sm2),max(sm3,sm4));
		 tot=r-l+1;	tot=tot-((mmax-sm1)+(mmax-sm2)+(mmax-sm3)+(mmax-sm4));
		 
	}cout<<ans<<endl;return 0;


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值