ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

《算法竞赛进阶指南》 第二章 Acwing 139. 回文子串的最大长度

2021-05-18 13:33:01  阅读:193  来源: 互联网

标签:cpStr 进阶 int unsigned len long 139 回文 Acwing


地址 https://www.acwing.com/problem/content/141/

如果一个字符串正着读和倒着读是一样的,则称它是回文的。
给定一个长度为 N 的字符串 S,求他的最长回文子串的长度是多少。

输入格式
输入将包含最多 30 个测试用例,每个测试用例占一行,以最多 1000000 个小写字符的形式给出。
输入以一个以字符串 END 开头的行表示输入终止。

输出格式
对于输入中的每个测试用例,输出测试用例编号和最大回文子串的长度(参考样例格式)。
每个输出占一行。

输入样例:
abcbabcbabcba
abacacbaaaab
END
输出样例:
Case 1: 13
Case 2: 6

解答

  1. 前置知识 字符串哈希
    对于一个长度为len的字符串str 可以使用一个数组 unsigned long long hashV[N] 来记录
    1~n的 字符串的哈希值 hashV[i]=hashV[i-1]x131 + str[i]-'a'+1;
    对于a到b的区间字符串的哈希值就是 hashV[b] - hashV[a]x131^(b-a+1)

那么计算出字符串的正序和逆序哈希值
以每个点展开向两旁扩展 获取哈希值 如果每个点两边的哈希值一致 那么它就是回文串记录回文串长度,返回最大值即可.

  1. 回文判断有aba和aabb两种,中间填充符号就可以直接划分为一种判断方式了
    比如转化为 a#b#a a#a#b#b

  2. 考虑到数据量较大 判断回文串的长度使用二分比遍历要快,否则会tle

// Ac139.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <algorithm>
#include <memory.h>


using namespace std;


/*
如果一个字符串正着读和倒着读是一样的,则称它是回文的。

给定一个长度为 N 的字符串 S,求他的最长回文子串的长度是多少。

输入格式
输入将包含最多 30 个测试用例,每个测试用例占一行,以最多 1000000 个小写字符的形式给出。

输入以一个以字符串 END 开头的行表示输入终止。

输出格式
对于输入中的每个测试用例,输出测试用例编号和最大回文子串的长度(参考样例格式)。

每个输出占一行。

输入样例:
abcbabcbabcba
abacacbaaaab
END
输出样例:
Case 1: 13
Case 2: 6
*/


const int N = 2001000;
//const int N = 1001000;
unsigned long long lh[N];
unsigned long long rh[N];
unsigned long long p[N];
const int base = 131;
char str[N];
char cpStr[N];
int ans = 1;


unsigned long long GetHashVl(unsigned long long h[N], int l, int r)
{
	return h[r] - h[l - 1] * p[r - l + 1];
}

unsigned long long GetHashVr(unsigned long long h[N], int l, int r)
{
	return h[l] - h[r + 1] * p[r - l + 1];
}

int GetRealLen(int len, char c) {
	if (c == '#') {
		if (len % 2 == 0) return len;
		else return (len / 2 + 1) * 2;
	}
	else {
		if (len % 2 == 0) return len + 1;
		else return (len / 2) * 2 + 1;
	}
}

int main()
{
	int idx = 1;
	while (1) {
		ans = 1;
		memset(cpStr, 0, sizeof(cpStr));
		memset(lh, 0, sizeof lh);
		memset(rh, 0, sizeof lh);

 
		scanf("%s", str + 1);
		if (strcmp(str + 1, "END") == 0) { break; }
		int len = strlen(str + 1);
		memset(cpStr, 0, sizeof(cpStr));
		for (int i = 0; i < len; i++) {
			cpStr[i * 2 + 1] = str[i + 1];
			cpStr[i * 2 + 2] = '#';
		}
        
		//计算正向逆向的哈希值的 然后遍历字节得到以遍历点为中心的最长回文长度
		len = strlen(cpStr + 1) - 1;
		cpStr[len + 1] = '\0';
		p[0] = 1;
		for (int i = 1; i <= len; i++) {
			lh[i] = lh[i - 1] * base + cpStr[i] - 'a' + 1;
			int j = len - i + 1;
			rh[j] = rh[j + 1] * base + cpStr[j] - 'a' + 1;
			p[i] = p[i - 1] * base;
		}

		for (int i = 1; i <= len; i++) {
			int r = min(i - 1, len - i);
			int l = 0;

			while (l < r) {
				int mid = (l + r+1) >> 1;
				if (GetHashVl(lh, i - mid, i) != GetHashVr(rh, i, i + mid)) {
					r = mid-1;
				}
				else {
					l = mid ;
				}
			}

			int realLen = GetRealLen(l, cpStr[i]);
			ans = max(ans, realLen);
		}

		printf("Case %d: %d\n", idx++, ans);
	}


	return 0;
}

我的视频题解空间

标签:cpStr,进阶,int,unsigned,len,long,139,回文,Acwing
来源: https://www.cnblogs.com/itdef/p/14780528.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有