1. 回文串

作为程序员,回文串这个词已经见怪不怪了,就是一个字符串正着读和反着读是一样的,形式如abcdcba、bbaabb。这里涉及到奇回文和偶回文,奇回文指回文串的字符数是奇数,偶回文指回文串的字符数是偶数。前面举的abcdcba就是奇回文,bbaabb就是偶回文。判断一个字符串是否是回文串很简单,只要从字符串的两端开始往中间扫描,全部匹配成功则是回文串,只要有一次匹配失败,那么就不是回文串。代码如下

// 没有对字符串为null或者空串的返回值进行考虑

static boolean Palindrome(String s){

for(int i = 0, j = s.length()-1; i < j; i , j--){

if(s.charAt(i) != s.charAt(j)){

return false;

}

}

return true;

}

2. 最长回文串

在我们了解回文串内容后,如果给你一个字符串,你能不能得到该字符串中的最长回文串呢?

2.1 暴力匹配法

最长回文串简单的解法就是暴力匹配法,依次判断所有字符数大于1个的子串是否回文串,并记录最长的那个回文串。如acbc字符串,得到字符数大于1的子串ac、cb、bc;acb、cbc;acbc,其中cbc是最长回文串。虽然暴力匹配法思路清晰、代码简单,但是如果字符串长度较长时,那么子串的数量是很庞大的,对于一个长度为n的字符串,它的子串有n(n-1)/2个,加上判断子串是否为回文串的时间复杂度是O(n),所以最终总的时间复杂度是O(n^3)左右。暴力匹配留给大家自行编写代码,博主就偷个懒不写了。

2.2 中心扩散法

中心扩散法是另一种回文串解决方法,算法思路是从字符串的第一个字符一直遍历到最后一个字符,每次从该字符往两边扫描,如果左右两边的值相等,那么往左右两边拓展,直至左右两边的值不相等或者越界,扫描结束,记录此时的左右边界下标,并且记录此时的回文串长度。该方法的时间消耗主要是遍历字符串的每个字符,以及每个字符需要向两边拓展扩散,所以总的时间复杂度为O(n^2)。

图解:以下以abcfcbd字符串遍历到 f 字符进行图解,如下图。

1. 当遍历abcfcbd字符串的 f 字符时,先令left和right都指向 f 字符。

2. 往左右拓展,可以拓展,left往左移,right往右移

3. 可以拓展,继续移动

4. 不可以继续拓展,结束,记录left和right的位置

代码

public String longestPalindrome(String s) {

int len = s.length();

if(len <= 1){

return s;

}

int max = 0;

int[] index = new int[2];

for(int i = 0; i < len-1; i ){

// 考虑奇数回文还是偶数回文,所以分别计算以i为中心,以i和i 1为中心两种方式的回文串

int[] f1 = findSub(s, i, i);

int[] f2 = findSub(s, i, i 1);

int f1Len = f1[1] - f1[0];

int f2Len = f2[1] - f2[0];

// 如果以i为中心的奇回文串长度更长并且大于前面记录的最大回文串长度max,更新max

// 如果以i和i 1为中心的偶回文串长度更长并且大于前面记录的最大回文串长度max,更新max

if((f1Len > f2Len) && (f1Len > max)){

index[0] = f1[0];

index[1] = f1[1];

max = f1Len;

}else if((f1Len <= f2Len) && (f2Len > max)){

index[0] = f2[0];

index[1] = f2[1];

max = f2Len;

}

}

return s.substring(index[0], index[1] 1);

}

static int[] findSub(String s, int left, int right){

// 如果是偶数回文,left和right不等,需要判断一下left和right的值是否相等

if(s.charAt(left) != s.charAt(right)){

return new int[]{left 1, left 1};

}

while((left >= 0) && (right <= s.length()-1) && (s.charAt(left) == s.charAt(right))){

left--;

right ;

}

return new int[]{left 1, right-1};

}

2.3 Manacher算法

Manacher算法是一种以O(n)时间复杂度得到最长回文串的算法,以该算法的发明者Manacher老先生名字命名。虽然该算法的解释网上较多,但是有点繁琐和难懂,博主尽量以自己小白的理解力详细地进行说明。我们接下来先说说Manacher算法的主要思想,它到底在哪里进行了优化?然后我们再上代码。接下来我们以dcbcdcbca字符串为例,请耐心阅读。

2.3.1. 对字符串dcbcdcbca先预处理。

在每个字符两旁插入分割符,可以是任意字符,因为博主一开始也觉得分隔符不能是字符串中出现的字符,那这里选取'a'字符作为分割符进行证明,预处理后得到如下字符串str2。

2.3.2. 记录每个字符的回文半径

遍历每个字符时,将每个字符可以向左右两边拓展的长度称为回文半径,使用val数组记录回文半径。则str2的第1个字符到第13个字符回文半径数据值如下图所示。

2.3.3 Manacher算法的优化之处

其实计算str2的第1个字符到第13个字符回文半径时Manacher也有优化,只是接下来更好讲解,所以现在分析。

当扫描到str2的第10个字符d时,此时的回文字符串是acabacadacabaca,如下图所示。

接下来我们要计算str2的第14个字符 b,正常情况下,我们以b为中心向两边拓展;Manacher算法的强大就是在此处进行了优化。

因为b处在axis和right之间,我们可以看看str2第14个b字符关于axis对称的第6个b字符它的回文半径是多少,为什么可以这样呢?

接下来看图解吧,原本以为自己理解了很好描述,但现在发现自己理解而已,要想描述清楚还是有点难,大家看看图解吧!

1. 步骤1

2. 步骤2

3. 步骤3

总结:Manacher算法进行优化的部分主要有两点:①字符串预处理,添加分割符;②利用回文串的对称信息,避免重复计算回文半径。

看来这种算法还是有些难描述的,大家见谅,还是只能多花点时间去消化,Manacher算法最重要一点就是利用对称信息。

代码

public String longestPalindrome(String s) {

int len = s.length();

int newLen = 2 * len 1;

// 字符串预处理,得到填充分隔符后的字符数组

char[] newStr = new char[newLen];

for(int i = 0; i < len; i ){

newStr[2*i] = 'a';

newStr[2*i 1] = s.charAt(i);

}

newStr[newLen-1] = 'a';

// ans是最长回文串的回文半径,ansIndex是最长回文串的对称中心

int[] val = new int[newLen];

int axis = 0;

int right = 0;

int ans = 0;

int ansIndex = 0;

for(int i = 0; i < newLen; i ){

// 如果当前遍历字符处于回文串的最远边界内,那么可以利用对称信息

if(i < right){

val[i] = Math.min(val[2*axis-i], right-i 1);

}else{

val[i] = 1;

}

// 没有越界,并且回文串向左右拓展成功,那么回文半径加1

while(i-val[i] >= 0 && i val[i] < newLen && newStr[i-val[i]] == newStr[i val[i]]){

val[i] ;

}

// 如果当前遍历字符的边界大于记录的最远边界,更新回文串的最远边界

if(i val[i]-1 > right){

right = i val[i]-1;

axis = i;

}

// 记录最长回文串的回文半径和对称中心

if(val[i] > ans){

ans = val[i];

ansIndex = i;

}

}

StringBuilder sb = new StringBuilder();

for(int i = ansIndex-ans 1; i < ansIndex ans-1; i ){

sb.append(newStr[ i]);

}

return sb.toString();

}

以下是力扣的运行结果

来源:https://www.icode9.com/content-1-789301.html

java 最长回文串_通俗易懂的最长回文串图解、说明及Java代码(中心扩散法和Manacher算法)...相关推荐

  1. 通俗易懂的最长回文串图解、说明及Java代码(中心扩散法和Manacher算法)

    1. 回文串 作为程序员,回文串这个词已经见怪不怪了,就是一个字符串正着读和反着读是一样的,形式如abcdcba.bbaabb.这里涉及到奇回文和偶回文,奇回文指回文串的字符数是奇数,偶回文指回文串的 ...

  2. python五位回文数_蓝桥杯,特殊回文数,Python

    题目 问题描述 123321是一个非常特殊的数,它从左边读和从右边读是一样的. 输入一个正整数n, 编程求所有这样的五位和六位十进制数,满足各位数字之和等于n . 输入格式 输入一行,包含一个正整数n ...

  3. java中暴力是啥方法_[蓝桥杯][历届试题]回文数字 中规中矩的暴力方法(Java代码)...

    解题思路: 1.直接暴力好了,只有5位和6位 注意事项: 1.如果没有暴力出一条结果,那么记得输出-1 参考代码:import java.util.Scanner; public class Main ...

  4. java前端接收回显图片_图片上传并回显后端篇

    图片上传并回显后端篇 我们先看一下效果 继上一篇的图片上传和回显,我们来实战一下图片上传的整个过程,今天我们将打通前后端,我们来真实的了解一下,我们上传的文件,是以什么样的形式上传到服务器,难道也是一 ...

  5. 微信小程序css 华文琥珀_琥珀项目:较小的,面向生产力的Java语言功能

    微信小程序css 华文琥珀 Brian Goetz最近的消息欢迎来到琥珀! 介绍Project Amber ( OpenJDK的一部分, 最初于1月提出 ). Goetz通过介绍"欢迎使用A ...

  6. java非主流火星文输入法_‎App Store 上的“火星文键盘-抽象话非主流输入法”...

    火星文键盘是一款的炫酷的火星文输入法.你不仅可以方便地输入火星文,并且还可以乱序文字,转换抽象话.未来也会更新聊天室等更多炫酷功能. 用户需要先使用其他输入法,或者系统内置的语音输入,输入想要转换的文 ...

  7. java中级教程下载,JAVA中级教程讲解全收录_通俗易懂版找工作必备(念安小姐姐主讲)...

    001_Html的介绍 002_Html的整体结构 003_常用标签(标题和水平线.段落和换行.图片.a标签) 004_frame框架集.div和span.表格table 005_列表.表单标签.表单 ...

  8. PS长图快速切片_关于公众号长图排版及一些bug

    许久没更新专栏了,因为一直忙着工作,所以把个人的许多账号都拉下了,以后时间可能会多起来.以后一定经常更新. 开门见山啊,来聊聊公众号长图的事情. 我知道很多接触过公众号的朋友,都知道怎么编辑长图,不知 ...

  9. jsdoc api文档_创建更好的JSDoc文档

    jsdoc api文档 Writing code documentation is one of the most relaxing experiences of my work as a back ...

最新文章

  1. PAT甲级1072 Gas Station (30 分):[C++题解]dijkstra算法、最短路
  2. nginx 配置expires
  3. 文献学习(part80-A)--Do we Need Hundreds of Classifiers to Solve Real World Classification Problems?
  4. Spring @Value注解无法正确赋值问题
  5. python numpy教程_Python中的Numpy入门教程
  6. php二进制加密_怎样给PHP源代码加密?PHP二进制加密与解密的解决办法
  7. 和 Python 2.x 说再见!
  8. oracle两个数据库之间,如何实现oracle两个数据库之间的同步
  9. 松下抛却Jungle掌机研发项目
  10. Tomcat5的数据库连接池配置
  11. 线性系统的Matlab分析函数
  12. 使用ActiveMQ实现简易聊天功能
  13. PS中有哪些快速抠图的方法
  14. 关于.Net WebProxy【转】
  15. python 还原九宫格图片_教你用python将图片变成九宫格,打造高逼格朋友圈九宫格图片...
  16. 报警器语音ic单片机芯片如何选型
  17. 扎心了,5年多工作经验,期望工资15k,HR只给了13k
  18. 第7关:求解一元二次方程
  19. html控制智能家居,一种通过web控制的智能家居系统的制作方法
  20. 新版的Eclipse安装的插件都在哪里?

热门文章

  1. Python基础教程:__setattr__和__delattr__和__getattr__的用法
  2. Matplotlib的画图的补充(Matplotlib的疑难杂症)
  3. Leetcode 534打劫房屋II python
  4. 22. loacte命令
  5. wxWidgets:wxTreebook类用法
  6. wxWidgets:wxSingleChoiceDialog类用法
  7. wxWidgets:wxProcess类用法
  8. boost::python::converter::arg_to_python相关的测试程序
  9. boost::mp11::mp_replace_at_c相关用法的测试程序
  10. boost::function_types::result_type用法的测试程序