尺取法 ------- 平衡字符串

问题描述

一个长度为 n 的字符串 s,其中仅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符。

如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。

现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?

如果 s 已经平衡则输出0。

Input

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

Output

一个整数表示答案

Sample Input_1

QWER

Sample Output_1

0

Sample Input_2

QQQQ

Sample Output_2

3

解题思路以及关键代码

① l , r 表示左右两个指针,初始化为l = 0, r = -1;
(如果数组是从1开始的,l = 1, r = 0;)
②由于区间内的字母可以随意更改,我们可以先统计区间外的4种字母的数量,然后找到数量最多的字母的数量maxx
③模拟填平操作,total代表区间里面所有元素的个数,free代表填平后剩余的个数

int maxx=max(max(sum1,sum2),max(sum3,sum4));
//填平操作
int total=r-l+1;
int free = total-(maxx-sum1)-(maxx-sum2)-(maxx-sum3)-(maxx-sum4);

④如果剩余个数>=0并且是4的倍数 表示满足条件,此时l++并且维护sum关系,试图去寻找一个更短的连续区间(r++对答案没有贡献,因为可以将r++的那一个元素保持不变)
反之,不满足时r++,试图使当前区间满足条件

if(l <= r && free >=0 && free % 4 == 0) 
		{ 
			ans = min(ans,total);
			if(s[l]=='Q') sum1++;
			if(s[l]=='W') sum2++;
			if(s[l]=='E') sum3++;
			if(s[l]=='R') sum4++;
			l++;  // [l,r] 符合条件 - l++
		}
		else
		{	
			r++;  // [l,r] 不符合条件 - r++
			if(r < n)
			{
				if(s[r]=='Q') sum1--;
				if(s[r]=='W') sum2--;
				if(s[r]=='E') sum3--;
				if(s[r]=='R') sum4--;	
			}		
		}

全部代码

// 1. 答案一定在一个连续区间
// 2. 区间的端点移动有明确方向的
#include<iostream>
#include<string>
using namespace std;
int ans=100000,sum1=0,sum2=0,sum3=0,sum4=0;
string s;
int main()
{
	cin>>s;
	int n = s.size();
	for(int i=0;i<n;i++)
	{
		if(s[i]=='Q')
			sum1++;
		if(s[i]=='W')
			sum2++;
		if(s[i]=='E')
			sum3++;
		if(s[i]=='R')
			sum4++;
	}
	if(sum1==sum2&&sum2==sum3&&sum3==sum4)
	{
		cout<<0;
		return 0;
	}
	int l = 0, r = -1;
	while(r < n)
	{
		int maxx=max(max(sum1,sum2),max(sum3,sum4));
		//填平操作
		int total=r-l+1;
		int free = total-(maxx-sum1)-(maxx-sum2)-(maxx-sum3)-(maxx-sum4);  
		if(l <= r && free >=0 && free % 4 == 0) 
		{ 
			ans = min(ans,total);
			if(s[l]=='Q') sum1++;
			if(s[l]=='W') sum2++;
			if(s[l]=='E') sum3++;
			if(s[l]=='R') sum4++;
			l++;  // [l,r] 符合条件 - l++
		}
		else
		{	
			r++;  // [l,r] 不符合条件 - r++
			if(r < n)
			{
				if(s[r]=='Q') sum1--;
				if(s[r]=='W') sum2--;
				if(s[r]=='E') sum3--;
				if(s[r]=='R') sum4--;	
			}		
		}
	}
	cout<<ans;
	return 0;
 } 

关于尺取法的总结

什么时候使用尺取法?
所求解的答案为一个连续的区间,并且区间左右端点移动有明确的方向。

经典例题,上述平衡字符串 以及 长度最小的连续区间sum和 >= S(给定常数)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值