POJ - 3974 Palindrome 字符串hash实现求最长回文子串

题目描述

给定一个字符串, 要求求出他的最长回文子串
包含多个输入, 以END结束

样例

Sample Input
abcbabcbabcba
abacacbaaaab
END
Sample Output
Case 1: 13
Case 2: 6

思路

  • 我们枚举每个字符,求以他为中心的最长回文串, 记录最长的一段,就是最终结果
  • 对于回文串是偶数的情况, 我们把原串都在他们的两个字符间加入一个和原来的不相干字符,就可以在不敢变原来串的情况下,把所有情况都改变成奇数
  • 枚举时我们用到二分优化
  • 建立hash值时, 我们创建一个正序suml和一个倒序sumr记录字符串的hash值, 在寻找以某个点为中心的回文串时, 我们用到一个正序, 一个倒序的长度为mid的hash值, 在求倒序的时候, 需要将下标映射。
    代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;

typedef unsigned long long ULL;
const int N = 2000010, M = 13331;

int suml[N], sumr[N], p[N];
char s[N];

ULL query(int sum[], int l, int r)
{
	return sum[r] - sum[l - 1] * p[r - l + 1]; 
}

int main()
{
	int t = 1;
	p[0] = 1;
	for(int i = 1; i < N; i++)
		p[i] = p[i - 1] * M;
	while(~scanf("%s", s + 1))
	{
		if(strcmp(s + 1, "END") == 0)
			break;
		
		int n = strlen(s + 1);
		for(int i = n * 2 ; i > 0; i -= 2)
		{
			s[i] = s[i / 2];
			s[i - 1] = 'z' + 1;
		}
		n *= 2;
		for(int i = 1, j = n; i <= n; i++, j--)
		{
			suml[i] = suml[i - 1] * M + s[i] - 'a' + 1;
			sumr[i] = sumr[i - 1] * M + s[j] - 'a' + 1; 
		}
		
		int ans = 0;
		for(int i = 1; i<= n; i++)
		{
			int l = 0, r = min(i - 1, n - i);
			while(l < r)
			{
				int mid = (l + r + 1) >> 1;
				if(query(suml, i - mid, i - 1) != query(sumr, n - (i + mid) + 1, n - (i + 1) + 1)) r = mid - 1;
				else l = mid;
			}
			if(s[i - l] == 'z' + 1)
				ans = max(ans, l);
			else ans = max(ans, l + 1);
		}
		printf("Case %d: %d\n", t++, ans);
		
	}
	
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值