题目大意:

给出一个字符串,包含‘r’、‘w’、‘b’三种字符。将字符串首尾相连,需要求出r…rb…b或b…br…r这种形式的子串的长度最大为多少。其中字符‘w’可以随意充当另外两种字符。

思路:

本题在求解过程中使用了贪心思想。
对于给出的字符串(暂时不考虑字符串中的字符全部相同的情况,此情况下直接输出字符串长度即可),可以将其分解为不同的子串r…rb…b或b…br…r(此时‘w’充当了其它两种字符串)。
那么现在就可以将问题分成两种情况进行讨论:
1.最长子串是r…rb…b的形式。
2.最长子串是b…br…r的形式。
不管哪种情况,最长子串都可以分为两个连续部分,其中一部分全是字符‘r’,简称r部,另一部分全是字符‘b’,简称b部。

接下来运用到了贪心思想。
可以想象到,对于最长子串来说,r部、b部都应尽可能的长。例如rrbbbrb的最长子串为rrbbb,其r部和b部都在条件范围内尽可能的伸展到最大。
这个结论是解题的关键。引出了本题的核心思想:
对于一个给出的字符串,找出所有的子串rb与br,并将这些子串的r部与b部延伸至最大。子串r部与b部之和的最大值就是所求答案。

下面我们针对“最长子串是r…rb…b的形式”这种情况进行详细解释。
建立两个数组r[]、b[]。
其中r[i]表示从字符串的位置i开始向左延伸的r部最大长度。
b[i]表示从字符串的位置i开始向左延伸的b部最大长度。
在初始化r[]的过程中,字符串‘w’全部充当为‘r’。
同理,在初始化b[]的过程中,字符串‘w’全部充当为‘b’。

接着,我们对字符串进行遍历,找出所有的子串rb,并求出其延伸后的长度。
举例来说,有一个字符串片段…b(rrrbbb)r…其中括号内是一个无法延伸的子串。
假设字符串片段中最右侧的字符‘r’在字符串内的位置为i。
那么括号内子串的b部长度则为b[i-1],r部长度为r[i-b[i-1]-1]。r部与b部之和即为括号内子串的长度。
按此方法可以求出所有r…rb…b形式子串的长度。与其类似,再求出所有b…br…r形式子串的长度,其中最大值即为答案。

代码:

/*
ID: lujunda1
LANG: C++
PROG: beads
*/
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdio>
using namespace std;
#define datasize 10000
char necklace[datasize],temp_r[datasize],temp_b[datasize];
int len,r[datasize],b[datasize];
int init()
{
	strcpy(temp_r,necklace);
	strcpy(temp_b,necklace);
	//将‘w’全部转换为‘r’或‘b’。 
	for(int i=0;i<len;i++)
		if(necklace[i]=='w')
		{
			temp_r[i]='r';
			temp_b[i]='b';
		}
	memset(r,0,sizeof(r));
	memset(b,0,sizeof(b));
	//下面是初始化r[]、b[]数组的操作。
	//与上文叙述有一点偏差的是r[i]表示从字符串的位置i开始向左延伸的r部“最大长度-1”。b[]同理。
	//循环条件为何为 i<len*2 而不是 i<len ? 
	//因为字符串实际表示一个环,例如:rrrbrrr b[]={3,4,5,0,0,1,2} 而不是 b[]={0,1,2,0,0,1,2}。 
	for(int i=1;i<len*2;i++)
	{
		if(temp_r[i%len]=='r'&&temp_r[(i-1)%len]=='r')
			r[i%len]=r[(i-1)%len]+1;
		if(temp_b[i%len]=='b'&&temp_b[(i-1)%len]=='b')
			b[i%len]=b[(i-1)%len]+1;
	}
}
//判断一个字符串其字符是否全部相同。 
bool check(char temp[])
{
	for(int i=1;i<len;i++)
		if(temp[i]!=temp[i-1])
			return false;
	return true;
}
int main()
{
	freopen("beads.in","r",stdin);
	freopen("beads.out","w",stdout);
	cin>>len>>necklace;
	init();
	//判断一个字符串是否只有除‘w’以外的一种字符。 
	if(check(temp_r)&&check(temp_b))
	{
		cout<<len<<endl;
		return 0;
	}
	int max=0;
	for(int i=0;i<len;i++)
	{
		//在尽可能r部最长的情况下(‘w’充当‘r’)寻找子串rb。
		//为什么不是 i-1 而是 (len+i-1)%len ?
		//这是考虑到 i=0 时的情况。当 i==0 时,位置i的前一位不是 -1 而是 len-1(最后一位)。 
		if(temp_r[i]=='b'&&temp_r[(len+i-1)%len]=='r')
		{
			//r部长度为r[(len+i-1)%len]+1,b部长度为b[(len+i-r部长度-1)%len]。
			//为什么不是 i-r部长度-1 而是 (len+i-r部长度-1)%len ?
			//因为这是考虑到了 i-r部长度-1 可能小于0。 
			int temp_max=b[(len+i-r[(len+i-1)%len]-2)%len]+r[(len+i-1)%len]+2;
			max=max>temp_max?max:temp_max;
		}
		if(temp_b[i]=='r'&&temp_b[(len+i-1)%len]=='b')
		{
			int temp_max=r[(len+i-b[(len+i-1)%len]-2)%len]+b[(len+i-1)%len]+2;
			max=max>temp_max?max:temp_max;
		}
	}
	//在上述计算过程中,在字符串本身就是其最大子串的情况下,max的值可能大于len。此时直接输出len即可。 
	if(max<=len)
		cout<<max<<endl;
	else
		cout<<len<<endl;
}