Manacher 马拉车算法

Manacher 马拉车算法

5. 最长回文子串 - 力扣(LeetCode)

马拉车算法是目前解决寻找字符串中最长的回文子串时间复杂度最低的算法(线性O(n)).

中心扩散法

初始化一个长度与字符串 s 相等的 臂长数组 arr 和 最长臂长 max 与 最长臂长回文串中心下标 maxIndex , 对字符串 s 进行迭代 , 初始化两个指针 leftright 分别指向当前位置 i 的两边 , 以判断当前位置字符的左右字符是否相等 和 左右下标是否超过数组边界 , 若相等且不超过边界则指针向外扩散并再次判断 . 退出判断后检测更新 maxmaxIndex .

原始的中心扩散法只能处理奇数回文串中心的情况 . 因此需要对原始字符串进行映射扩充 : 在开头 , 结尾以及字符之间插入任意一个相同的 , 非字符串可能存在的字段的特殊字符 ( 一般为 # ) , 这样字符串的长度由 n 映射到 2*n+1 , 如果出现偶数回文串中心的情况 , 映射到新字符串则是落在特殊字符上 , 最后还原即可 , 这样保证了对字符串臂长的计算均建立在奇数中心的情况 .

观察最坏情况 : 字符串每个字符均相同 , 长度为 n , 则对于每个字符串均需要左右指针扩散计算 , 从 0 次 到 n/2 次 再到 0 次 , 得到计算次数大致为 n^2/4 次 , 时间复杂度为 O(n^2) .

import java.util.StringJoiner;
class Solution {public String longestPalindrome(String s) {int n = s.length();StringJoiner sj = new StringJoiner("#", "#", "#");for(int i = 0; i < n; ++i) {sj.add(s.substring(i, i + 1));}int number = sj.toString().length();char[] charArr = sj.toString().toCharArray();int[] arr = new int[number];int max = 0;int maxIndex = 0;int left, right;for(int i = 0; i < number; ++i) {left = i - 1;right = i + 1;while(left >= 0 && right < number) {if(charArr[left] == charArr[right]){++arr[i];--left;++right;}else break;}if(arr[i] > max) {max = arr[i];maxIndex = i;}}max = (max - 1) / 2;if((maxIndex - 1) % 2 == 1) { // 偶数中心maxIndex = (maxIndex - 1) / 2;return s.substring(maxIndex - max, maxIndex + max + 2);}maxIndex = (maxIndex - 1) / 2;return s.substring(maxIndex - max, maxIndex + max + 1);}
}

Manacher 对中心扩散法的优化

中心扩散法对每个字符进行计算明显具有冗余 , Manacher 马拉车算法的目的即是尽可能的减少计算 , 降低时间复杂度 : 注意到回文串的臂长具有 对称性 : 回文串以中心点为对称轴 , 其左右两侧的字符是相等的 , 回文串最远距离内任意非中心字符的臂长可以继承对应字符的臂长 . 为了实现这一便利 , 我们需要在每次迭代时额外维护两个量 最右边界r 和 最右边界对应的大回文串中心centerIndex .

arr[i] = Math.min(r - i, arr[2 * centerIndex - i]); 是算法的核心语句 , 可以认为当回文子字符的臂长没有超过大回文的边界时 , 我们对该该字符是 完全知悉的 , 臂长在大回文内即被截断 . 若镜像点的回文半径较小以至于其完全包含在以 centerIndex 为中心的大回文串中 , 那么当前字符的回文半径可以直接继承完全知悉的镜像点 arr[2 * centerIndex - i] , 不需要再进行计算 ; 若镜像点的回文半径较大以至于超出了大回文串的边界 , 则当前字符的回文半径至少可以继承到大回文的最右边界right - i , 而我们对大回文外的字符分布并不知悉 , 因此后续需要计算尝试扩展 .

同样观察最坏情况 : 字符串的每个字符均相同 , 对于前半字符串的每个位置 n 需要计算 n-(n-1)1 次 , 后半字符串因为镜像点始终完全知悉 , 直接继承即可 , 计算次数也为 1 次 , 总计算次数为 n 次 , 时间复杂度为 O(n) .

class Solution {public String longestPalindrome(String s) {int n = s.length();StringBuilder sb = new StringBuilder();sb.append("#");for(int i = 0; i < n; ++i) {sb.append(s.substring(i, i + 1)).append("#");}int number = sb.toString().length();char[] charArr = sb.toString().toCharArray();int[] arr = new int[number];int max = 0;int maxIndex = 0;int r = maxIndex + max;int centerIndex = 0;int left, right;for(int i = 0; i < number; ++i) {left = i - 1;right = i + 1;if(i <= r) {arr[i] = Math.min(r - i, arr[2 * centerIndex - i]); // Manacher核心语句left -= arr[i];right += arr[i];}while(left >= 0 && right < number && charArr[left] == charArr[right]) {++arr[i];--left;++right;}if(arr[i] > max) {max = arr[i];maxIndex = i;}if(r < arr[i] + i) {r = arr[i] + i;centerIndex = i;}}int start = (maxIndex - max) / 2;int end = start + max;return s.substring(start, end);}
}

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

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

相关文章

(学习总结29)Linux 进程概念和进程状态

Linux 进程概念 冯诺依曼体系结构软件运行与存储分级数据流动的理论过程 操作系统操作系统(Operator System) 概念操作系统的功能与作用系统调用和库函数概念 进程概念描述进程 - PCBtask_struct查看进程通过系统调用获取进程标示符 PID通过系统调用 fork 函数创建进程简单使用…

MySQL密码修改的全部方式一篇详解

本文将详细介绍多种修改MySQL密码的方式。 本文目录 一、alter user 语句操作步骤 二、set password操作步骤 三、直接修改 mysql.user表操作步骤 一、alter user 语句 当你以 root 用户或者拥有足够权限的用户登录 MySQL 时&#xff0c;可以使用 ALTER USER 语句来修改密码。…

Wi-Fi NAN 架构(Wi-Fi Aware Specification v4.0,第2章:2.3~2.6)

1. NAN 数据通信架构 1.1 单播支持 要在两个NAN设备之间启动单播数据通信&#xff0c;服务需发起一个NAN数据路径&#xff08;NDP&#xff0c;NAN Data Path&#xff09;请求。这对NAN设备之间会建立一个NAN设备链路&#xff08;NDL&#xff0c;NAN Device Link&#xff09;&…

Lineageos 22.1(Android 15)实现负一屏

一、前言 方案是参考的这位大佬的&#xff0c;大家可以去付费订阅支持一波。我大概理一下Android15的修改。 大佬的方案代码 二、Android15适配调整 1.bp调整&#xff0c;加入aidl引入&#xff0c;这样make之后就可以索引代码了 filegroup {name: "launcher-src"…

Java 大视界 -- Java 大数据在智能医疗远程会诊与专家协作中的技术支持(146)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

Sqlite3数据库

工具库的使用&#xff1a;程序编写时#include <库名.h>即可调用库中的函数 编译时链接工具库&#xff1b; 注意&#xff1a;数据库中不区分字母大小写&#xff1b; SQLite 中的事务是数据库操作中非常重要的一个概念&#xff0c;它用于确保数据库操作的完整性和一致性。…

虚拟路由与单页应用(SPA):详解

在单页应用&#xff08;SPA&#xff0c;Single Page Application&#xff09;中&#xff0c;虚拟路由&#xff08;也称为前端路由&#xff09;是一种关键的技术&#xff0c;用于管理页面导航和状态变化&#xff0c;而无需重新加载整个页面。为了帮助你更好地理解这一概念&#…

练习:运动计划

需求&#xff1a;键盘录入星期数&#xff0c;显示今天的减肥活动。 周一&#xff1a;跑步&#xff1b; 周二&#xff1a;游泳&#xff1b; 周三&#xff1a;慢走&#xff1b; 周四&#xff1a;骑动感单车&#xff1b; 周五&#xff1a;拳击&#xff1b; 周六&#xff1a;…

通过webrtc+canvas+css实现简单的电脑滤镜拍照效果

这里我们用的是webrtc中的MediaDevices.getUserMedia()的浏览器api进行的效果实现&#xff0c;MediaDevices.getUserMedia() 会提示用户给予使用媒体输入的许可&#xff0c;媒体输入会产生一个MediaStream&#xff0c;里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道…

《TCP/IP网络编程》学习笔记 | Chapter 20:Windows 中的线程同步

《TCP/IP网络编程》学习笔记 | Chapter 20&#xff1a;Windows 中的线程同步 《TCP/IP网络编程》学习笔记 | Chapter 20&#xff1a;Windows 中的线程同步用户模式和内核模式用户模式同步内核模式同步 基于 CRITICAL_SECTION 的同步内核模式的同步方法基于互斥量对象的同步基于…

VBA-Excel

VBA 一、数据类型与变量 常用数据类型&#xff1a; Byte&#xff1a;字节型&#xff0c;0~255。Integer&#xff1a;整数型&#xff0c;用于存储整数值&#xff0c;范围 -32768 到 32767。Long&#xff1a;长整型&#xff0c;可存储更大范围的整数&#xff0c;范围 -214748364…

kotlin 内联函数 inline

高阶函数实现的原理&#xff1a;函数类型其实是生成了一个对象 。 inline翻译成中文的意思就是内联&#xff0c;在kotlin里面inline被用来修饰函数&#xff0c;表明当前函数在编译时是以内嵌的形式进行编译的&#xff0c;从而减少了一层函数调用栈&#xff1a; inline fun fun…

PairRE: Knowledge Graph Embeddings via Paired Relation Vectors(论文笔记)

CCF等级&#xff1a;A 发布时间&#xff1a;2020年11月 25年3月24日交 目录 一、简介 二、原理 1.整体 2.关系模式 3.优化模型 三、实验性能 四、结论和未来工作 一、简介 将RotatE进行生级&#xff0c;RotatE只对头实体h进行计算&#xff0c;PairRE对头尾实体都进行…

从报错到成功:Mermaid 流程图语法避坑指南✨

&#x1f680; 从报错到成功&#xff1a;Mermaid 流程图语法避坑指南 &#x1f680; &#x1f6a8; 问题背景 在开发文档或技术博客中&#xff0c;我们经常使用 Mermaid 流程图 来可视化代码逻辑。但最近我在尝试绘制一个 Java Stream 转换流程图时&#xff0c;遭遇了以下报错…

深入解析 Redis 实现分布式锁的最佳实践

前言 在分布式系统中&#xff0c;多个进程或线程可能会同时访问同一个共享资源&#xff0c;这就可能导致数据不一致的问题。为了保证数据的一致性&#xff0c;我们通常需要使用分布式锁。Redis 作为高性能的内存数据库&#xff0c;提供了一种简单高效的方式来实现分布式锁。本…

2025年03月10日人慧前端面试(外包滴滴)

目录 普通函数和箭头函数的区别loader 和 plugin 的区别webpack 怎么实现分包&#xff0c;为什么要分包webpack 的构建流程变量提升react 开发中遇到过什么问题什么是闭包vue 开发中遇到过什么问题vue中的 dep 和 watcher 的依赖收集是什么阶段什么是原型链react setState 是同…

Android10 系统截屏功能异常的处理

客户反馈的问题&#xff0c;设备上使用状态栏中“长截屏”功能&#xff0c;截屏失败且出现系统卡死问题。 在此记录该问题的处理 一现象&#xff1a; 设备A10上使用系统“长截屏”功能&#xff0c;出现截屏失败&#xff0c;系统死机。 二复现问题并分析 使用设备操作该功能&…

openvela新时代的国产开源RTOS系统

openvela 简介 openvela 操作系统专为 AIoT 领域量身定制&#xff0c;以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势&#xff0c;已成为众多物联网设备和 AI 硬件的技术首选&#xff0c;涵盖了智能手表、运动手环、智能音箱、耳机、智能家…

ENSP学习day9

ACL访问控制列表实验 ACL&#xff08;Access Control List&#xff0c;访问控制列表&#xff09;是一种用于控制用户或系统对资源&#xff08;如文件、文件夹、网络等&#xff09;访问权限的机制。通过ACL&#xff0c;系统管理员可以定义哪些用户或系统可以访问特定资源&#x…

JVM的组成--运行时数据区

JVM的组成 1、类加载器&#xff08;ClassLoader&#xff09; 类加载器负责将字节码文件从文件系统中加载到JVM中&#xff0c;分为&#xff1a;加载、链接&#xff08;验证、准备、解析&#xff09;、和初始化三个阶段 2、运行时数据区 运行时数据区包括&#xff1a;程序计数…