【字符串】马拉车(Manacher)算法

news2024/12/29 1:23:03

本篇文章参考:比较易懂的 Manacher(马拉车)算法配图详解

马拉车算法可以求出一个字符串中的最长回文子串,时间复杂度 O ( n ) O(n) O(n)

因为字符串长度的奇偶性,回文子串的中心可能是一个字符,也可能是两个字符中间的位置,所以为了解决这个问题,我们在每两个字符之间加一个 # ,开头再加一个 $ 防止越界

比如说:

abcd 变成 $#a#b#c#d#

接下来是后文需要的一些定义:

  • c 表示当前已经计算过的最靠右的回文子串的中心点的下标
  • m 表示以 c 为中心的回文子串的右端点下标
  • p[i] 表示以 s[i] 为中心的回文子串的半径(包括自身)

对于以每一个位置为中心点的时候单独计算,复杂度很大,马拉车可以对其进行很好地优化

目前的难点就是怎么计算 p[i]

在这里插入图片描述

看上面这张图,我们当前需要计算 p[i],我们可以去找 i 关于 c 的对称点(记为 j),因为我们是从左往右计算的,所以 p[j] 已经计算过了,如果以 j 为中心的回文子串在以 c 为中心的回文子串中时,我们可以直接把 p[j] 赋给 p[i]

当然会出现一些特殊情况:

  • 如果 p[j] + i > m,如下图所示,以 c 为中心的回文子串包不住,我们就更新 p[i] = m - i (先只更新确定的部分)
    在这里插入图片描述
  • 如果 i 在 m 右侧,如下图所示,更新 p[i] = 1
    在这里插入图片描述

上面的情况都只能得到半成品的 p[i],所以需要对 s[i] 进行中心扩展,得到最终的 p[i]

如果最终的 p[i] + i > m 此时已经有比以 c 为中心的回文子串更靠右的回文子串了,就把 c = i m = p[i] + 1

求完 p[i] 后算法结束

求最长回文子串板子

string Manacher(string s)
{
	int sl = s.size(); // 原字符串长度
	if (sl == 0 || sl == 1) return s;

	// 构建新串
	string ns = "$#";
	for (int i = 0; i < sl; i ++ )
	{
		ns += s[i];
		ns += '#';
	}

	int len = ns.size();
	int c = 0; // 最靠右的回文子串的中心点下标
	int m = 0; // 最靠右的回文子串的右端点下标
	int pos = 0; // 最长回文子串的中心点
	int maxlen = 0; // 最长回文子串的半径(不包括中心点)(新字符串中)
	vector<int> p(len); // p[i]表示以i为中心点的回文子串的半径(包括i)
	for (int i = 1; i < len; i ++ )
	{
		if (i < m) p[i] = min(p[c - (i - c)], m - i + 1); // c-(i-c)是i关于c的对称点 当前情况表示i在目前最靠右侧的回文子串中
		else p[i] = 1 + (ns[i] != '#'); // 当前不是#的话 其两侧就是# 所以半径可以加1

		if (i - p[i] >= 0 && i + p[i] < ns.size())
			while (ns[i - p[i]] == ns[i + p[i]]) p[i] ++ ; // 对半成品的i位置进行中心扩散

		if (i + p[i] - 1 > m) // 产生了比以c为中心时更靠右的回文子串
		{
			c = i;
			m = i + p[i] - 1;
		}

		if (p[i] - 1 > maxlen) // 更新最长回文子串
		{
			maxlen = p[i] - 1;
			pos = i;
		}
	}
	string ans = "";
	char tmp;
	for (int i = 0; i < 2 * maxlen * 1; i ++ ) // 遍历最长字串的每个位置 得出原字符串中的最长字串
	{
		tmp = ns[pos - (maxlen - 1) + i];
		if (tmp != '#') ans += tmp;
	}
	return ans;
}

求最长前缀or后缀回文子串板子

string Manacher(string s)
{
	int sl = s.size(); // 原字符串长度
	if (sl == 0 || sl == 1) return s;

	// 构建新串
	string ns = "$#";
	for (int i = 0; i < sl; i ++ )
	{
		ns += s[i];
		ns += '#';
	}

	int len = ns.size();
	int c = 0; // 最靠右的回文子串的中心点下标
	int m = 0; // 最靠右的回文子串的右端点下标
	int pos = 0; // 最长回文子串的中心点
	int maxlen = 0; // 最长回文子串的半径(不包括中心点)(新字符串中)
	// int flag; // 可以用这个标记是前缀回文子串最长还是后缀回文子串最长
	vector<int> p(len); // p[i]表示以i为中心点的回文子串的半径(包括i)
	for (int i = 1; i < len; i ++ )
	{
		if (i < m) p[i] = min(p[c - (i - c)], m - i + 1); // c-(i-c)是i关于c的对称点 当前情况表示i在目前最靠右侧的回文子串中
		else p[i] = 1 + (ns[i] != '#'); // 当前不是#的话 其两侧就是# 所以半径可以加1

		if (i - p[i] >= 0 && i + p[i] < ns.size())
			while (ns[i - p[i]] == ns[i + p[i]]) p[i] ++ ; // 对半成品的i位置进行中心扩散

		if (i + p[i] - 1 > m) // 产生了比以c为中心时更靠右的回文子串
		{
			c = i;
			m = i + p[i] - 1;
		}

		if (p[i] == i && maxlen < p[i]) // 最长前缀回文子串
		{
			maxlen = p[i] - 1;
			pos = i;
			// flag = 1;
		}
		if (p[i] + i == len && maxlen < p[i]) // 最长后缀回文子串
		{
			maxlen = p[i] - 1;
			pos = i;
			// flag = 2;
		}
	}
	string ans = "";
	char tmp;
	for (int i = 0; i < 2 * maxlen * 1; i ++ ) // 遍历最长字串的每个位置 得出原字符串中的最长字串
	{
		tmp = ns[pos - (maxlen - 1) + i];
		if (tmp != '#') ans += tmp;
	}
	return ans;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1486917.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧草莓基地:Java与SpringBoot的技术革新

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

ue4.27 发现 getRandomReachedLocation 返回 false

把这个玩意儿删掉&#xff0c;重启工程&#xff0c;即可 如果还不行 保证运动物体在 volum 内部&#xff0c;也就是绿色范围内确保 project setting 里面的 navigation system 中 auto create navigation data 是打开的(看到过博客说关掉&#xff0c;不知道为啥) 如果还不行&…

STM32学习和实践笔记(1): 装好了的keil μVision 5

2019年3月在淘宝上买了这块STM32的开发板&#xff0c;学了一段时间后就丢下了&#xff0c;今天重新捡起来&#xff0c;决定好好学习、天天向上。 对照教程&#xff0c;今天先把keil5装上了。 装的过程有以下几点值得记录下&#xff1a; 1&#xff09;用注册机时&#xff0c;…

【数据结构】B树

1 B树介绍 B树&#xff08;英语&#xff1a;B-tree&#xff09;&#xff0c;是一种在计算机科学自平衡的树&#xff0c;能够保持数据有序。这种数据结构能够让查找数据、顺序访问、插入数据及删除的动作&#xff0c;都在对数时间内完成。B树&#xff0c;概括来说是一个一般化的…

波斯猫 6页面 宠物动物 长毛猫 HTML5 带背景音乐 JS图片轮播特效 滚动文字 鼠标经过图片 JS时间代码

波斯猫 6页面 宠物动物 长毛猫 HTML5 带背景音乐 JS图片轮播特效 滚动文字 鼠标经过图片 JS时间代码 注册表单 宠物网页成品 海量学生网页成品 个人博客 人物明星 城市家乡 旅游景点 美食特产 购物电商 公司企业 学校大学 科普教育 宠物动物 鲜花花卉 植物水果 茶叶咖啡 健康生…

【前端寻宝之路】学习如何使用HTML实现简历展示和填写

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-iJ3Ou0qMGFVaqVQq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

Google Dremel和parquet的复杂嵌套数据结构表征方法解析

转载请注明出处。作者&#xff1a;archimekai 核心参考文献&#xff1a; Dremel: Interactive Analysis of Web-Scale Datasets 文章目录 引言复杂嵌套数据结构的无损表征问题Dremel论文中提出的表征方法parquet备注 引言 Dremel是Google的交互式分析系统。Google大量采用prot…

LabVIEW石油钻机提升系统数字孪生技术

LabVIEW石油钻机提升系统数字孪生技术 随着数字化、信息化、智能化的发展&#xff0c;石油钻采过程中的石油钻机数字化技术提升成为了提高钻井效率、降低生产成本的重要途径。基于中石油云平台提供的数据&#xff0c;采用数字孪生技术&#xff0c;对石油钻机提升系统进行数字化…

设计模式(十三)抽象工厂模式

请直接看原文:设计模式&#xff08;十三&#xff09;抽象工厂模式_抽象工厂模式告诉我们,要针对接口而不是实现进行设计。( )-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- …

Some collections -- 2024.3

一、TensorFlow Android (dataset: Mnist) We used TensorFlow to define and train our machine learning model, which can recognize handwritten numbers, called a number classifier model in machine learning terminology. We transform the trained TensorFlow mod…

pytest-allure报告生成

pytest生成allure报告步骤&#xff1a; 下载allure&#xff0c;配置allure报告的环境变量&#xff1a;把allure-2.13.7\bin 配置到环境变量path路径 验证&#xff1a;在dos窗口和pycharm窗口分别验证&#xff1a;allure –version 2. 生成临时的json报告 在pytest.ini配置文…

挑战杯 基于深度学习的中文情感分类 - 卷积神经网络 情感分类 情感分析 情感识别 评论情感分类

文章目录 1 前言2 情感文本分类2.1 参考论文2.2 输入层2.3 第一层卷积层&#xff1a;2.4 池化层&#xff1a;2.5 全连接softmax层&#xff1a;2.6 训练方案 3 实现3.1 sentence部分3.2 filters部分3.3 featuremaps部分3.4 1max部分3.5 concat1max部分3.6 关键代码 4 实现效果4.…

【k8s管理--可视化界面】

1、可视化界面的软件 kubernetes的可视化软件有以下这些kubernetes dashboard&#xff1a;https://github.com/kubernetes/dashboardkubesphere官网&#xff1a; https://kubesphere.io/zh/rancher 官网&#xff1a; https://www.rancher.cn/kuboard 官网&#xff1a; https:/…

基于STC12C5A60S2系列1T 8051单片机的TM1638键盘数码管模块的数码管显示应用

基于STC12C5A60S2系列1T 8051单片机的TM1638键盘数码管模块的数码管显示应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍TM1638键盘数码管模块概述TM1638键盘数码管…

Matlab 多项式插值(曲线拟合)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 由于对曲线拟合有些兴趣,这里就找了一些资料从最基本的方法来看一下曲线拟合的效果: 二、实现代码 % **********

【Git】深入理解 Git 分支合并操作:git merge dev 命令详解

深入理解 Git 合并操作&#xff1a;git merge dev 命令详解 摘要&#xff1a;本文将深入探讨 Git 中的合并操作&#xff0c;以及如何使用 git merge dev 命令将dev 分支的修改合并到当前分支&#xff08;假设当前分支为main 分支&#xff09;中。通过详细的解释和示意图&#x…

【笔记】【电子科大 离散数学】 3.谓词逻辑

谓词引入 因为含变量的语句&#xff08;例如x > 3&#xff09;不是命题&#xff0c;无法进行逻辑推理。 为了研究简单命题句子内部的逻辑关系&#xff0c;我们需要对简单命题进行分解&#xff0c;利用个体词&#xff0c;谓词和量词来描述它们&#xff0c;并研究个体与总体…

django MTV 静态文件js的添加方式,以及怎么优化js的加载

django MTV 静态文件js的添加方式,以及怎么优化js的加载 1&#xff1a;怎么添加js 2&#xff1a;怎么优化js的加载 django MTV 需要用到的js时&#xff0c;使用以下方式 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF…

NACOS在Windows和Linux下的安装教程

目录 1、Windows安装 1.1、下载安装包 1.2、解压 1.3、端口配置 1.4、启动 1.5、访问 2、Linux安装 2.1、安装JDK 2.2、上传安装包 2.3、解压 2.4、端口配置 2.5、启动 3、Nacos的依赖 1、Windows安装 开发阶段采用单机安装即可。 1.1、下载安装包 在Nacos的Git…

LeetCode 面试题 08.09.括号

括号。设计一种算法&#xff0c;打印n对括号的所有合法的&#xff08;例如&#xff0c;开闭一一对应&#xff09;组合。 说明&#xff1a;解集不能包含重复的子集。 例如&#xff0c;给出 n 3&#xff0c;生成结果为&#xff1a; [ “((()))”, “(()())”, “(())()”, “…