hihocoder 1032 最长回文子串 (Manacher算法 详解+模板)

2024-03-20 13:38

本文主要是介绍hihocoder 1032 最长回文子串 (Manacher算法 详解+模板),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

时间限制:1000ms
单点时限:1000ms
内存限制:64MB

描述

   小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。

   这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?”

   小Ho奇怪的问道:“什么叫做最长回文子串呢?”

   小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的身为回文串的子串啦~”

   小Ho道:“原来如此!那么我该怎么得到这些字符串呢?我又应该怎么告诉你我所计算出的最长回文子串呢?

   小Hi笑着说道:“这个很容易啦,你只需要写一个程序,先从标准输入读取一个整数N(N<=30),代表我给你的字符串的个数,然后接下来的就是我要给你的那N个字符串(字符串长度<=10^6)啦。而你要告诉我你的答案的话,只要将你计算出的最长回文子串的长度按照我给你的顺序依次输出到标准输出就可以了!你看这就是一个例子。”

提示一提示二提示三提示四
样例输入
3
abababa
aaaabaa
acacdas
样例输出
7
5
3 

题目链接:http://hihocoder.com/problemset/problem/1032


题目分析:Manacher算法可以在O(n)的时间复杂度内解决最长回文子串问题,下面介绍一下这个算法

首先对于一个任意长度的字符串,通过插入无关字符法均可以将其变成奇数长度,如aba => #a#b#a#,abba => #a#b#b#a#,为了解决边界问题可以直接在最前面再加上一个无关字符,令cur为当前能延伸到最右端的回文子串的中心位置,p[cur]表示当前能延伸到最右端的回文子串的回文半径,而p[cur] + cur就是当前能延伸到的最右端,当前位置i如果在其范围之外,即p[cur] + cur < i则p[i] = 1(自己另起一段回文子串),如果p[cur] + cur >= i,也就是当前位置在其范围内,则此时p[i] = min(p[cur * 2 - i],p[cur] + cur - i),这里分两种情况,1) p[cur * 2 - i] > p[cur] + cur - i,也就是说以i当前的对称点为中心的回文子串范围在当前cur为中心的回文子串的最左端的左边,则这时p[i] = p[cur] + cur - i;p[cur] + cur - i指的是当前cur为中心的回文串的最右端到当前点i的距离,2) p[cur * 2 - i] <= p[cur] + cur - i,情况类似上面,画图很容易看出来,算出p[i],则以当前的i为中心向两端扩展,若扩展出来的最右端超过原来的最右端则更新cur

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int const MAX = 1e6 + 5;
char s[MAX << 1];
int p[MAX << 1];int Manacher()
{int len = strlen(s);for(int i = len; i >= 0; i--){s[(i << 1) + 2] = s[i];s[(i << 1) + 1] = '#';}s[0] = '*';int cur = 0, ans = 0;for(int i = 2; i < 2 * len + 1; i++){if(p[cur] + cur >= i)p[i] = min(p[(cur << 1) - i], p[cur] + cur - i);elsep[i] = 1;while(s[i - p[i]] == s[i + p[i]])p[i] ++;if(p[cur] + cur < i + p[i])cur = i;ans = max(ans, p[i]);}return ans - 1;
}int main()
{int n;scanf("%d", &n);while(n --){scanf("%s", s);printf("%d\n", Manacher());}
}


这篇关于hihocoder 1032 最长回文子串 (Manacher算法 详解+模板)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/829617

相关文章

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

MySQL中between and的基本用法、范围查询示例详解

《MySQL中betweenand的基本用法、范围查询示例详解》BETWEENAND操作符在MySQL中用于选择在两个值之间的数据,包括边界值,它支持数值和日期类型,示例展示了如何使用BETWEEN... 目录一、between and语法二、使用示例2.1、betwphpeen and数值查询2.2、be

python中的flask_sqlalchemy的使用及示例详解

《python中的flask_sqlalchemy的使用及示例详解》文章主要介绍了在使用SQLAlchemy创建模型实例时,通过元类动态创建实例的方式,并说明了如何在实例化时执行__init__方法,... 目录@orm.reconstructorSQLAlchemy的回滚关联其他模型数据库基本操作将数据添

Java中ArrayList与顺序表示例详解

《Java中ArrayList与顺序表示例详解》顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构,:本文主要介绍Java中ArrayList与... 目录前言一、Java集合框架核心接口与分类ArrayList二、顺序表数据结构中的顺序表三、常用代码手动

JAVA线程的周期及调度机制详解

《JAVA线程的周期及调度机制详解》Java线程的生命周期包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,线程调度依赖操作系统,采用抢占... 目录Java线程的生命周期线程状态转换示例代码JAVA线程调度机制优先级设置示例注意事项JAVA线程

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

C++构造函数中explicit详解

《C++构造函数中explicit详解》explicit关键字用于修饰单参数构造函数或可以看作单参数的构造函数,阻止编译器进行隐式类型转换或拷贝初始化,本文就来介绍explicit的使用,感兴趣的可以... 目录1. 什么是explicit2. 隐式转换的问题3.explicit的使用示例基本用法多参数构造

Java利用Spire.Doc for Java实现在模板的基础上创建Word文档

《Java利用Spire.DocforJava实现在模板的基础上创建Word文档》在日常开发中,我们经常需要根据特定数据动态生成Word文档,本文将深入探讨如何利用强大的Java库Spire.Do... 目录1. Spire.Doc for Java 库介绍与安装特点与优势Maven 依赖配置2. 通过替换

Android使用java实现网络连通性检查详解

《Android使用java实现网络连通性检查详解》这篇文章主要为大家详细介绍了Android使用java实现网络连通性检查的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录NetCheck.Java(可直接拷贝)使用示例(Activity/Fragment 内)权限要求

MyBatis中的两种参数传递类型详解(示例代码)

《MyBatis中的两种参数传递类型详解(示例代码)》文章介绍了MyBatis中传递多个参数的两种方式,使用Map和使用@Param注解或封装POJO,Map方式适用于动态、不固定的参数,但可读性和安... 目录✅ android方式一:使用Map<String, Object>✅ 方式二:使用@Param