背景

近期開始研究算法,于是在leetcode上做算法题,第五题Longest Palindromic Substring便是关于回文子串的。

什么是回文字串

回文字符串是指将该字符串前后颠倒之后和该字符串一样的字符串。比如:a,aaaa,aba,abba…

最长回文子串

要求最长回文子串,就须要遍历每个子串,时间复杂度是O(N²);推断字串是不是回文,时间复杂度是O(N),这种话算法的时间复杂度就是O(N³).

我刚開始想到的就是中心扩展法,代码例如以下:

public static String getLongestPalindrome(String str) {
if(str.isEmpty() || str.length() == 1) {
return str;
} String longest = str.substring(0, 1);
for (int i = 0; i < str.length(); i++) {
// get longest palindrome with center of i
String tmp = helper(str, i, i);
if (tmp.length() > longest.length()) {
longest = tmp;
} // get longest palindrome with center of i, i+1
tmp = helper(str, i, i + 1);
if (tmp.length() > longest.length()) {
longest = tmp;
}
}
return longest;
} private static String helper(String str, int begin, int end) {
while (begin >= 0 && end <= str.length() - 1
&& str.charAt(begin) == str.charAt(end)) {
begin--;
end++;
}
String result = str.substring(begin + 1, end);
return result;
}

中心扩展法的时间复杂度为O(N²).

写完之后一直在想,有没有更厉害的办法呢。能将时间复杂度杀到O(N)呢,一直想也想不到,后来上网搜到了传说中的Manacher算法。

我们先来看一下代码:

public static int[] getPalindromeLength(String str) {
StringBuilder newStr = new StringBuilder();
newStr.append("#");
for(int i = 0; i < str.length(); i++) {
newStr.append(str.charAt(i));
newStr.append("#");
} int[] rad = new int[newStr.length()]; // the right edge of the longest sub palindrome string
int right = -1;
// the center of the longest sub palindrome string
int id = -1; for (int i = 0; i < newStr.length(); i++) {
// define the minimum radius
int r = 1;
if (i <= right) {
r = Math.min(right - i, rad[2 * id - i]);
} // try to get a lager radius
while (i - r >= 0 && i + r < newStr.length()
&& newStr.charAt(i - r) == newStr.charAt(i + r)) {
r++;
} //update the right edge and the center of the longest sub palindrome string
if (i + r - 1> right) {
right = i + r - 1;
id = i;
}
rad[i] = r;
} return rad;
}

首先。Manacher算法提供了一个巧妙解决长度为奇数与长度为偶数的不同回文办法。在每一个字符见插入一个原字符串未出现过的特殊字符,普通情况下用“#”。

这样无论是aba类型的回文还是abba类型的回文。插入特殊字符之后,#a#b#a#和#a#b#b#a#的长度肯定是奇数,这样就攻克了上面的问题。

Manacher算法引入一个辅助数组来记录以每一个字符为中心的最长回文串的信息,Rad[i]记录的是以字符str[i]为中心的最长回文串。当以str[i]为中心,这个最长回文串向两边延伸Rad[i]个字符。

原串:abbac

新串:#a#b#b#a#c#

辅助数组:12 1 2 5 2 1 2 1 2 1

那么Manacher算法是怎么计算辅助数组Rad的呢?

我们从左往右依次计算Rad[i],当计算Rad[i]时,Rad[j](0<=j<i)已经计算完成。

我们如果整型right为当前最长回文子串的最右边缘。而且设当前最长回文子串的中心点为id,那么当前指针的位置i就有两种情况:

第一种:i<=right

那么找到i相对于中心点的对称的位置j(2*id-i)。那么假设Rad[j]<right-i。例如以下图:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

那么说明以j为中心的回文串一定在以id为中心的回文串的内部,且j和i关于位置id对称,由回文串的定义可知。一个回文串反过来还是一个回文串,所以以i为中心的回文串的长度至少和以j为中心的回文串一样,即Rad[i]>=Rad[j]。由于Rad[j]<right-i。所以说i+Rad[j]<right。由对称性可知Rad[i]=Rad[j]。

假设Rad[j]>=right-i,由对称性。说明以i为中心的回文串可能会延伸到right之外,而大于right的部分我们还没有进行匹配。所以要从right+1位置開始一个一个进行匹配,直到发生失配,从而更新right和相应的id以及Rad[i]。

另外一种情况:i>right

假设i比right还要大,说明对于中点为i的回文串还一点都没有匹配,这个时候,就仅仅能老老实实地一个一个匹配了。匹配完毕后要更新right的位置和相应的id以及Rad[i]。

总结

1.  Manacher算法先巧妙的在全部字符间插入特殊字符,非常好的攻克了回文字串偶数长度和奇数长度不同处理方法的问题。

2.  事实上Manacher算法的复杂度不仅仅O(N),可是显然是介于O(N)和O(N²)之间,是眼下时间复杂度最低的回文子串算法。

【LeetCode-面试算法经典-Java实现】【05-Longest Palindromic Substring(最大回文字符串)】的更多相关文章

  1. leetcode 5 Longest Palindromic Substring--最长回文字符串

    问题描述 Given a string S, find the longest palindromic substring in S. You may assume that the maximum ...

  2. 【LeetCode】5. Longest Palindromic Substring 最大回文子串

    题目: Given a string S, find the longest palindromic substring in S. You may assume that the maximum l ...

  3. 5. Longest Palindromic Substring最大回文子串

    int sta = 0; int max = 1; public String longestPalindrome(String s) { /* 判断回文有两种: 1.最大回文子序列求长度: 用动态规 ...

  4. 【LeetCode-面试算法经典-Java实现】【008-String to Integer (atoi) (字符串转成整数)】

    [008-String to Integer (atoi) (字符串转成整数)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Implement atoi to co ...

  5. (python)leetcode刷题笔记05 Longest Palindromic Substring

    5. Longest Palindromic Substring Given a string s, find the longest palindromic substring in s. You ...

  6. [leetcode]516. Longest Palindromic Subsequence最大回文子序列

    Given a string s, find the longest palindromic subsequence's length in s. You may assume that the ma ...

  7. Longest Palindromic Substring-----最长回文子串

    首先讲讲什么是回文, 看看Wiki是怎么说的:回文,亦称回环,是正读反读都能读通的句子.亦有将文字排列成圆圈者,是一种修辞方式和文字游戏.回环运用得当.能够表现两种事物或现象相互依靠或排斥的关系, 比 ...

  8. leetcode:Longest Palindromic Substring(求最大的回文字符串)

    Question:Given a string S, find the longest palindromic substring in S. You may assume that the maxi ...

  9. 最长回文子串-LeetCode 5 Longest Palindromic Substring

    题目描述 Given a string S, find the longest palindromic substring in S. You may assume that the maximum ...

随机推荐

  1. RISC设计原则及基本技术

    CISC的特点: 指令系统庞大,指令功能复杂,指令寻址方式多,指令格式多 绝大多数指令须要多个机器周期完毕 各种指令都能够訪问存储器 採用微程序控制 有专用寄存器,少量 难以用优化编译技术生成高效的目 ...

  2. 好记性不如烂笔头86-spring3学习(7)-ApplicationContext中bean的生命周期

    假设使用ApplicationContext来生成.管理Bean, 一个Bean从建立到销毁,会历经几个运行阶段. 我个人理解一般的bean的生命周期主要包含:建立,初始化,使用阶段,销毁四个核心阶段 ...

  3. Data Member Order

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-member-order In some appl ...

  4. Nginx下部署TP5项目

    标签(空格分隔): linux nginx配置文件: server { listen 81; #listen [::]:80; server_name _; index index.html inde ...

  5. tomcat:Could not publish to the server. java.lang.IndexOutOfBoundsException

    1.将工程加入到tomcat,报上述错误 2. run--maven build 报jar包错误: invalid LOC header (bad signature) 3.根据提示找到上述jar包, ...

  6. PostgreSQL 批量生成数据

    create table user_info(userid int,name text,birthday date,crt_time timestamp without time zone,); in ...

  7. 《剑指offer》包含min函数的栈

    一.题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数. 二.输入描述 输入栈 三.输出描述 最小值 四.牛客网提供的框架 class Solution { public: ...

  8. AWK行处理的用法实例

    第一节 awk的工作流程及基础用法 awk操作符会先检索文件的行信息,然后在行信息里找需要的内容. Awk的默认分割付是空格,awk '/模式/{print $1,$2}' file ##模式的位置可 ...

  9. oracle 12c 关于wm_concat 的替换;LISTAGG

    之所以用到了wm_concat函数.是想到达这样的结果集. 转为这样的===========> 返回这样的数据,易与配合echarts的数据准备. 看上去十分的方便,但是遗憾的是,oracle极 ...

  10. laravel中soapServer支持wsdl的例子

    最近在对接客户的CRM系统,获取令牌时,要用DES方式加密解密,由于之前没有搞错这种加密方式,经过请教了"百度"和"谷歌"两个老师后,结合了多篇文档内容后,终于 ...