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

背景

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

什么是回文字串

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

最长回文子串

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

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

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(N2).

写完之后一直在想,有没有更厉害的办法呢。能将时间复杂度杀到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。例如以下图:

那么说明以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(N2)之间,是眼下时间复杂度最低的回文子串算法。

时间: 2024-10-14 03:11:33

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

【LeetCode-面试算法经典-Java实现】【009-Palindrome Number(回文数)】

[009-Palindrome Number(回文数)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Determine whether an integer is a palindrome. Do this without extra space. 题目大意 判断一个数字是否是回访字数,不要使用额外的空间. 解题思路 为了不使用额外的空间,参考了其它的解决,那些解法看起来在isPalindrome方法中没有使用额外参数,但是却使用了方法调用,这个比一个整数消耗的

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

题目: Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 思路:用Manacher算法得到最大回文子串的长度,得到带#的最大回文子串,用split剔除#后转化成String形式输出即可. public

5. Longest Palindromic Substring最大回文子串

int sta = 0; int max = 1; public String longestPalindrome(String s) { /* 判断回文有两种: 1.最大回文子序列求长度: 用动态规划,dp[sta][end] 代表开头为sta.结尾为end的部分最大回文子序列的长度是多少 dp[sta][end] = (s.charAt(sta)==s.charAt(end))?dp[sta+1][end-1]+2:max(dp[sta][end-1],dp[sta+1][end]) 2.最

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

[008-String to Integer (atoi) (字符串转成整数)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Implement atoi to convert a string to an integer. Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what

LeetCode【5】. Longest Palindromic Substring --java实现

Longest Palindromic Substring 一.题目如下:        Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 题目要求给定字符串的最大对称子字符串,如"aaabccbac

[LeetCode][Java]Longest Palindromic Substring

题目: Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 题意: 给定字符串S,找到该字符串中最长的回文子串.假设这个子串的最大长度为1000,并且这个最长回文子串是存在且唯一的. 算法分析: 回文字

[LeetCode] Longest Palindromic Substring [14]

题目 Given a string S, find the longest palindromic substring in S. You may assume that the maximum length ofS is 1000, and there exists one unique longest palindromic substring. 原题链接 解题思路 最长回文字串,相信做过Palindrome Partitioning II 这个题的同学应该可以很快做出来.没错,这个题还可以

LeetCode题解 #5 Longest Palindromic Substring

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 在给定一个字符串S中,找到最长的回文串. 很恶心的一道题,不过应该都能想到枚举,从第一个开始枚举.枚举的字母向两头延伸,如果相同则继续,不同则开始下一

[Java]LeetCode5 Longest Palindromic Substring

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 题意:求字符串中最长的回文 感觉这题不难,可以这样想,设置两个指针,分别对应0,len-1. 比如从第一个字符开始,abababac,我们可以找a出现