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

本篇文章参考:比较易懂的 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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

webpack源码分析——tapable中before和stage如何改变执行顺序

一、Before用法 Before 用法 before 属性的值可以传入一个数组或者字符串,值为注册事件对象时的名称&#xff0c;它可以修改当前事件函数在传入的事件名称对应的函数之前进行执行。 示例 let hook new SyncWaterfallHook([arg1]);hook.tap(tap1, (arg)> {console.log(tap1…

安装 node 错误的配置环境变量之后使用 npm 报错

安装 node 错误的配置环境变量之后使用 npm 报错 node:internal/modules/cjs/loader:1147 throw err; ^ Error: Cannot find module ‘F:\ACodeTools\Node\node_modules\npm\bin\node_modules\npm\bin\npm-cli.js’ at Module._resolveFilename (node:internal/modules/cjs/loa…

Git推送本地仓库至阿里云仓库

Git推送本地仓库至阿里云仓库 1.安装Git 参考Git安装详解 2.生成 SSH 密钥 基于RSA算法SSH 密钥 1.管理员权限运行Git Bash 2.输入生成密钥指令点击回车&#xff0c;选择 SSH 密钥生成路径。 $ ssh-keygen -t rsa -C "2267521563qq.com"3.以 RSA算法为例&…

TMGM官网平台联合英超豪门切尔西

TMGM官网平台联合英超豪门切尔西 TMGM澳洲总部客户经理 &#x1f30f;&#xff1a;TMGM818 TMGM中国官网【TMGM558】TMGM联合英超豪门切尔西俱乐部深度合作&#xff0c;去年全球客户成交额突破4650亿美元&#xff0c;在泰国曼谷周杰伦演唱会唯一平台品牌赞助商&#xff0c;作为…

IOC中Bean的生命周期

生命周期的各个阶段&#xff1a; 可以分为三个阶段&#xff1a;产生-使用-销毁 又可以分四个阶段&#xff1a;四个阶段 实例化 ->属性注入->初始化 ->销毁 实例化后到使用的初始化过程&#xff1a; 属性赋值 ->处理各种Aware接口->实现BeanPostProcessor的b…

数据结构/C++:二叉搜索树

数据结构/C&#xff1a;二叉搜索树 概念模拟实现结构分析插入中序遍历查找删除析构函数拷贝构造赋值重载递归查找递归插入递归删除 总代码展示 概念 二叉搜索树&#xff08;BST - Binary Search Tree&#xff09;是一种特殊的二叉树&#xff0c;每个顶点最多可以有两个子节点。…

逆向案例四:360k静态和精灵数据动态AES解密,用js的方法

一、360K 网页链接:https://www.36kr.com/p/2672600261670407 页面中有静态的需要解密的内容&#xff0c;确定html包&#xff0c;确定方法 1.1方法步骤 在下方的搜索中输入decrypt(或者关键字window.initialState &#xff0c;进入js文件 在AES.decrypt处打上断点&#xff0…

【Java项目介绍和界面搭建】拼图小游戏——键盘、鼠标事件

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

15-Linux部署HBase集群

Linux部署HBase集群 简介 HBase 是一种分布式、可扩展、支持海量数据存储的 NoSQL 数据库。 和Redis一样&#xff0c;HBase是一款KeyValue型存储的数据库。 不过和Redis设计方向不同 Redis设计为少量数据&#xff0c;超快检索HBase设计为海量数据&#xff0c;快速检索 HB…

运行Python文件时出现‘utf-8’code can‘t decode byte 如何解决?(如图)

如图 亦或者出现“SyntaxError: Non-UTF-8 code starting with \xbb ” 出现这种问题往往是编码格式导致的&#xff0c;我们可以在py文件中的第一行加入以下代码&#xff1a; # codingutf-8或者 # codinggdk优先使用gbk编码 解释一下常用的两种编码格式&#xff1a; utf-…

供应链管理(SCM):界面设计全面扫盲,得供应链者得天下

大家伙&#xff0c;我是大千UI工场&#xff0c;专注UI分享和项目接单&#xff0c;本期带来供应链系统的设计分享&#xff0c;欢迎大家关注、互动交流。 一、什么是SCM SCM系统是供应链管理&#xff08;Supply Chain Management&#xff09;系统的缩写。供应链管理是指协调和管…

CSS列表属性

CSS列表属性 列表相关的属性&#xff0c;可以作用在 ul、ol、li 元素上。 代码如下&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>列表相关属性</title><style>ul {/* …

MySQL的一行数据是如何存储的?

目录 1.COMPACT 行格式长什么样&#xff1f; 例子1&#xff1a;用户设置了主键值&#xff0c;列都是not null的。(默认字符集是utf8mb4,在这种情况下&#xff0c;char(N)类型就不是定长的了&#xff09; 例子2&#xff1a;没有设置主键&#xff0c;也没有唯一索引&#xff0…

微信小程序-生命周期

页面生命周期 onLoad: 页面加载时触发的方法&#xff0c;在这个方法中可以进行页面初始化的操作&#xff0c;如获取数据、设置页面状态等。 onShow: 页面显示时触发的方法&#xff0c;在用户进入页面或从其他页面返回该页面时会调用此方法。可以在此方法中进行页面数据刷新、动…

浅谈马尔科夫链蒙特卡罗方法(MCMC)算法的理解

1.解决的问题 计算机怎么在任意给定的概率分布P上采样&#xff1f;首先可以想到把它拆成两步&#xff1a; &#xff08;1&#xff09;首先等概率的从采样区间里取一个待定样本x&#xff0c;并得到它的概率为p(x) &#xff08;2&#xff09;然后在均匀分布U[0,1]上取一个值&a…

基于主从模式的Reactor的仿muduo网络库

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

分布式系统中常用的缓存方案

1. 引言 随着互联网应用的发展和规模的不断扩大&#xff0c;分布式系统中的缓存成为了提升性能和扩展性的重要手段之一。本文将介绍几种在分布式系统中常用的缓存方案&#xff0c;包括分布式内存缓存、分布式键值存储、分布式对象存储和缓存网关等。 1.1 缓存在分布式系统中的…

数据结构c版(3)——排序算法

本章我们来学习一下数据结构的排序算法&#xff01; 目录 1.排序的概念及其运用 1.1排序的概念 1.2 常见的排序算法 2.常见排序算法的实现 2.1 插入排序 2.1.1基本思想&#xff1a; 2.1.2直接插入排序&#xff1a; 2.1.3 希尔排序( 缩小增量排序 ) 2.2 选择排序 2.2…

WPS如何共享文件和文件夹

1 WPS共享单个文件 用WPS打开要分享的文件&#xff0c;点击右上角的“分享”键&#xff0c;选择上传到云端。 之后点击“创建并分享”&#xff0c;即可分享该文档。 2 WPS创建共享文件夹 2.1 如何共享文件夹 首先打开WPS&#xff0c;点击左上角的首页。在首页栏中&#…

Sqli-labs靶场第21、22关详解[Sqli-labs-less-21、22]自动化注入-SQLmap工具注入|sqlmap跑base64加密

Sqli-labs-Less-21、22 由于21/22雷同&#xff0c;都是需要登录后&#xff0c;注入点通过Cookie值进行测试&#xff0c;值base64加密 修改注入数据 选项&#xff1a;--tamperbase64encode #自动化注入-SQLmap工具注入 SQLmap用户手册&#xff1a;文档介绍 - sqlmap 用户手册 由…