hihoCoder第一周:求解最大回文串

回文串就好像aba,abba等,顺着读和反正读相同的字符串,那么如何在一个字符串中找到存在的最大回文串呢?

1.最简单暴力的办法,就是枚举字符串的每个子串,一一求解是否为回文串,最后得到最大的回文串长度。

void circle()
{
	char str[50];

	while(scanf("%s", str) != EOF)
	{
		int ans = 1;
		for(int i = 0; str[i]; i++)
			for(int j = i+1; str[j]; j++)
			{
				int flag = 0;
				int left = i;
				int right = j;
				while(left < right)
				{
					if(str[left] != str[right])
					{
						flag = 1;
						break;
					}
					left++;
					right--;
				}
				if(flag == 0 && (j - i + 1) > ans)
					ans = j - i + 1;
			}
		printf("%d\n", ans);
	}
}

这种方法用了一个三重循环,复杂度比较高,所以不推荐。


2.我们先考虑回文串长度为奇数的情况下,aba,ababa,前后都是关于中间的字母对称的,所以,我们可以根据中间的字母,分别求解以这个字母为中心的最长回文串。

可是,当回文串长度为偶数的时候,以上方法就显得不使用了,例如,abba,这里引入manchester方法,在每个字符中间插入一个‘#’,如此就将所有长度为偶数的回文串也变为奇数了。

void circle2()
{
	char s[50];
	char str[100];
	str[0] = '$';
	str[1] = '#';
	while(scanf("%s", s) != EOF)
	{
		int n = 2;
		for(int i = 0; s[i]; i++)
		{
			str[n++] = s[i];
			str[n++] = '#';
		}
		str[n] = '\0';
		printf("%s\n", str);
		int ans = 1;
		for(int i = 1; str[i]; i++)
		{
			int temp;
			if(str[i] == '#')
				temp = 0;
			else
				temp = 1;
			int left = i-1, right = i+1;
			while(str[left] == str[right])
			{
				if(str[left] != '#')
					temp += 2;
				left--;
				right++;
			}
			if (ans < temp)
			{
				ans = temp;
			}
		}
		printf("%d\n", ans);
	}
}


这种方法相比暴力法有了很大的提高,但如果字符串是aaaaaaa的时候,时间复杂度还是比较高,有没有更好的办法呢,那就是第三种方法了。


3.首先,我们知道对于偶数长度的回文串,abba,acbbca。中间两个字符一定是相同的,也必定构成回文串,并且,不论中间重复的字符个数是偶数还是奇数,都必定构成回文串,aaa,aaaa,于是就有了第三种方法,如果相邻字符相同,则直接将相同的字符连在一起当作一个字符考虑。例如abba,将bb当作S1,然后再计算,abbba,将bbb当作S2,然后计算,当遇到方法二中的最坏情况,即aaaaaaaa时,直接当作S3。

void circle3()
{
	char s[100];
	s[0] = '$';
	while(scanf("%s", s+1) != EOF)
	{
		int ans = 1;
		for(int i = 1; s[i]; i++)
		{
			int l, r, t;
			l = i;
			r = i;
			while(s[l] == s[r+1])r++;//处理回文串为偶数的情况
			i = r;
			while(s[l-1] == s[r+1])
			{
				l--;
				r++;
			}
			if((t = r-l+1) > ans)
				ans = t;
		}
		printf("%d\n", ans);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值