【题目】

给定一个字符串str,返回str中最长回文子串的长度

【举例】

str="123", 1

str=“abc1234321ab” 7

【暴力破解】

从左到右遍历字符串,遍历到每个字符的时候,以当前字符作为中心能够产生多大的回文字符串,

奇回文和偶 回文寻找方式不一样。

缺点:前面的寻找无法为后面的寻找提供任何帮助。没有记忆。加上记忆就好了。

【Manacher】

Manacher算法解决的问题是在线性时间内找到一个字符串的最长回文子串。

  1. 奇回文和偶回味在判断是比较麻烦,首先对str进行处理。插入 特殊字符。

    123 -》 #1#2#3#

通过这种处理方式,偶回文也有了中心轴。 解决了奇偶的差异性。

特殊字符# 用于对应的是自己。所以对整个求解无影响。

其中用到 i & 1 判断当前索引是 奇数还是偶数。参考这个

https://segmentfault.com/q/1010000021162482/a-1020000021164176

public static char[] manacherString(String str) {
char[] charArr = str.toCharArray();
char[] res = new char[2 * charArr.length + 1];
int index = 0;
for (int i = 0; i < res.length; i++) {
// i&1==0 表示 如果是 偶数
res[i] = (i & 1) == 0 ? '#' : charArr[index++];
}
return res;
}
  1. 处理后的字符串记为charArr.

    需要三个辅助变量
  • pArr: 长度与charArr长度一样。pArr[i]的含义是: 以 i 位置上的字符 charArr[i]作为 回文中心的情况下,扩出去得到的最大回文半径是多少。
  • pR: 这个变量是 之前遍历的所有 字符的所有回文半径中。 最右即将到达的位置。
  • index: 和pR联动。表示最右即将到达的位置 的回文中心位置。

3)从左到右依次算出数组pArr每个位置的值,最大的值 就是处理后的charArr中的最大回文半径。

中括号表示 index的回文左右边界。

小括号表示 i 和 i'的左右回文边界。

分俩大情况, 第二种情况再分为3小情况。

  • 第一种情况

当前的i,在pR之后,就暴力扩就对了。前面的回文信息提供不了任何帮助。

  • 第二种情况

    就是 i在pR之内。

index肯定在 i之前。

因为 i在 某一个元素的回文半径中,所以一定有对称点i'

根据i'的回文半径所处位置划分为三类

1)i'的回文半径 在 index的回文半径内。



i的回文半径就是和i'一样,不可能再大了。

证明:

首先X != Y

Y和Z是 index的对称点。 Y == Z

X和H是 index的对称点。 X == H

所以 Z != H 。所以 i的回文半径长度就是pArr[i']

2) i'的回文半径 超出了index的回文半径



]' [' 代表 以 i' 和 i 为对称的 []的位置。

现在证明 i的 最大回文半径应该是多少呢.

首先 [' 到 ]的位置肯定是回文。只需要看Z和H是否相等。

证明:

X和Y是 以 i'的对称点 。 X == Y。

Y和Z是 以 index的对称点。 Y==Z。 那么 X == Z。

X和H肯定不相等。因为如果相等。那么 index的最大回文半径就不是[]。 X!=H

那么Z!=H

那么 i的回文半径长度 就是 [' 到 ]

3)i'的回文半径 正好 和index的左边界 重合。

那么i最小的回文也是(到]。 因为Z和H是否相无法证明,需要比较了。

以上三种情况,扩出去的过程可以优化,但还是无法 避免扩出去的检查。

public static int maxLcpsLength(String str) {

        if (str == null || str.length() == 0) {
return 0;
} char[] charArr = manacherString(str);
System.out.println(Arrays.toString(charArr));
int[] pArr = new int[charArr.length];
int index = -1;
int pR = -1;
int max = Integer.MIN_VALUE; // 保存最大值。 for (int i = 0; i < charArr.length; i++) { if (pR > i) {
// i 在 pR内,看哪部分不需要比较了。 // i' 的 位置的 回文半径 大小
int pi_ = pArr[2 * index - i]; // 最远也只能扩到 pR . 最小 就是 看i'的回文半径 pi_ int pR_pi_ = pR - i; // i 到 pR的距离长度大小。
// 取最小值.三种情况都符合,也没有多余的浪费。
// 第一种。pR-i 肯定 大于 pi_ 所以没问题
// 第二种. pR-i 肯定 小于 pi_ 本来就是从pR开始扩,也没问题。
// 第三种. pR-i == pi_ 。
pArr[i] = Math.min(pi_, pR_pi_); // 当前 pArr[i] 的值得意思是 以 i为中心,这个半径之内的不需要验证了。后面的还需要比较一下。 } else {
// i 在 pR外。需要自己扩。
pArr[i] = 1;
}
// 以上 整合成一行就是
// pArr[i] = pR > i ? Math.min(pArr[2*index-1], pR-i):1;
while (i + pArr[i] < charArr.length && i - pArr[i] > -1) {
// 扩的停止条件就是 左右边界到了。
if (charArr[i + pArr[i]] == charArr[i - pArr[i]]) {
pArr[i]++;// 左右相等。继续扩。
} else {
// 无法继续扩了,退出。
break;
}
// 更新 pR 和 index ,如果当前 i位置的最右边界 和前面的一样,不更新。只有大于才更新。
if (i + pArr[i] > pR) {
pR = i + pArr[i];
index = i;
}
// 更新max
max = Math.max(max, pArr[i]);
}
} return max - 1; // }

max - 1 ,因为 加了辅助。需要减一。

算法:Manacher,给定一个字符串str,返回str中最长回文子串的长度。的更多相关文章

  1. Manacher算法----最长回文子串

    题目描述 给定一个字符串,求它的最长回文子串的长度. 分析与解法 最容易想到的办法是枚举所有的子串,分别判断其是否为回文.这个思路初看起来是正确的,但却做了很多无用功,如果一个长的子串包含另一个短一些 ...

  2. 最长回文子串—Manacher 算法 及 python实现

    最长回文子串问题:给定一个字符串,求它的最长回文子串长度.如果一个字符串正着读和反着读是一样的,那它就是回文串.   给定一个字符串,求它最长的回文子串长度,例如输入字符串'35534321',它的最 ...

  3. manacher算法求最长回文子串

    一:背景 给定一个字符串,求出其最长回文子串.例如: s="abcd",最长回文长度为 1: s="ababa",最长回文长度为 5: s="abcc ...

  4. leetcode 求一个字符串的最长回文子串

    最长回文子串问题:给定一个字符串,求它的最长回文子串长度.如果一个字符串正着读和反着读是一样的,那它就是回文串.   给定一个字符串,求它最长的回文子串长度,例如输入字符串'35534321',它的最 ...

  5. 51nod1089 最长回文子串 manacher算法

    0. 问题定义 最长回文子串问题:给定一个字符串,求它的最长回文子串长度. 如果一个字符串正着读和反着读是一样的,那它就是回文串.下面是一些回文串的实例: 12321 a aba abba aaaa ...

  6. 最长回文子串——manacher

    最长回文子串--Manacher 算法 (原版的博主的代码都是用py写的,这里改成c++) c++ 算法 字符串处理 0. 问题定义 最长回文子串问题:给定一个字符串,求它的最长回文子串长度. 如果一 ...

  7. hdu3068 求一个字符串中最长回文字符串的长度 Manacher算法

    最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  8. 最长回文子串(动规,中心扩散法,Manacher算法)

    题目 leetcode:5. Longest Palindromic Substring 解法 动态规划 时间复杂度\(O(n^2)\),空间复杂度\(O(n^2)\) 基本解法直接看代码 class ...

  9. Manacher模板( 线性求最长回文子串 )

    模板 #include<stdio.h> #include<string.h> #include<algorithm> #include<map> us ...

随机推荐

  1. 8.4 苹果macOS电脑如何安装Java开发环境(JDK)

    和Windows电脑安装差不多. 下载 来到JDK官方下载界面,点击Java SE 8(简称JDK 8)后面的JDK下载,来到该界面,先同意协议,然后下载对应平台的JDK,我们这里下载Mac OS X ...

  2. CSS基本知识点——带你走进CSS的新世界

    CSS基本知识点 我们在学习HTML之后,前端三件套第二件便是CSS,但CSS内容较多,我们分几部分讲解: (如果没有学习HTML,请参考之前文章:HTML知识点概括--一篇文章带你完全掌握HTML& ...

  3. 跨模态语义关联对齐检索-图像文本匹配(Image-Text Matching)

    论文介绍:Negative-Aware Attention Framework for Image-Text Matching (基于负感知注意力的图文匹配,CVPR2022) 代码主页:https: ...

  4. Cisco Packet Tracer Student(思科网络模拟器)模拟集线器和嗅探攻击

    一.集线器简介 集线器是局域网内的基础设备,工作于OSI中的物理层,作用是将接收的信号进行放大再传输,集线器是纯硬件设施,集线器开发之初就没考虑过软件层面的操作,所以不具备像路由器.交换机等设备那样具 ...

  5. ShardingSphere 云上实践:开箱即用的 ShardingSphere-Proxy 集群

    本次 Apache ShardingSphere 5.1.2 版本更新为大家带来了三大全新功能,其中之一即为使用 ShardingSphere-Proxy chart 在云环境中快速部署一套 Shar ...

  6. 01 开发App真机调试问题

    逍遥安卓模拟器 :https://juejin.cn/post/7062922018710093831 HBuilderX真机调试插上手机却提示"未检测到手机或浏览器"的问题:ht ...

  7. Scala学习第一天(Hello world)

    一.Scala介绍 1. Scala概念 Scala 是 Scalable Language 的简写,是一门多范式的编程语言 联邦理工学院洛桑(EPFL)的Martin Odersky于2001年基于 ...

  8. 字符串的操作和MAth工具类

    字符串的操作 常用方法 判断功能方法 equals(String s)判断两个字符串是否相同,区分大小写 equsalsignorecase(String s) 判断两个字符串是否相同,不区分大小写 ...

  9. 获取字典中values值中最大的数,返回对应的keys

    1.字典中键值对的获取 print(data.values()) # 查看字典的值 print(data.keys()) # 查看字典的key 2.对字典中的值进行排序 sorted(data.val ...

  10. python 异常捕捉与异常处理

    简介 在实际开发中,为了防止异常界面直接被用户看到,往往我们会采用捕捉异常的方式来进一步处理异常. 异常捕捉 如下代码由于下标越界会导致异常 data = range(10) print(data[1 ...