背景

近期開始研究算法,于是在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. Django Admin site 显示问题

    Django Admin site 显示问题 今天配置了一下Django admin site,可是admin site的显示有一些问题,当我打开源码.訪问里面的admin 的css 文件时候,htt ...

  2. WinRar 设置默认的压缩格式为zip

    By default, WinRar uses the RAR archive format for compressing files. You may prefer using the more ...

  3. uwsgi和wsgi

    一个Web应用的本质就是: 浏览器发送一个HTTP请求: 服务器收到请求,生成一个HTML文档: 服务器把HTML文档作为HTTP响应的Body发送给浏览器: 浏览器收到HTTP响应,从HTTP Bo ...

  4. MetaSploit攻击实例讲解------Metasploit自动化攻击(包括kali linux 2016.2(rolling) 和 BT5)

    不多说,直接上干货! 前期博客 Kali linux 2016.2(Rolling)里Metasploit连接(包括默认和自定义)的PostgreSQL数据库 Kali linux 2016.2(Ro ...

  5. 射击的乐趣:WIN32诠释打飞机游戏

    一楼留给链接http://blog.csdn.net/crocodile__/article/details/11860129 楼上神贴,膜拜片刻...... 一.游戏玩法和已经实现的功能 1.打开游 ...

  6. <Sicily> Longest Common Subsequence

    一.题目描述 Given a sequence A = < a1, a2, -, am >, let sequence B = < b1, b2, -, bk > be a s ...

  7. sql排名函数--四个

    1 row_number 2 rank 3 dense_rank 4 ntile 例子如下: select * into #MyTablefrom(select '语文' as 课程,70 as 成绩 ...

  8. 什么是Monad?

    为了理解什么是Monad,最好需要了解什么是Monoid.这两篇互为姐妹篇,因为Monad的定义是:A monad is just a monoid in the category of endofu ...

  9. 最小生成树(MST) prim() 算法 kruskal()算法 A - 还是畅通工程

    某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离. 省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公 ...

  10. mysql主从复制主服务器日志格式的区别

        statement(语句级别,从服务器直接把语句拿来执行):            影响一大片(插入很多条或修改很多条),就适合用 statement       row(行级别,从服务器直接 ...