求字符串的最长回文串-----Manacher's Algorithm 马拉车算法

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example 1:

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Example 2:

Input: "cbbd"
Output: "bb"

思路一:求每一个子串,但是要知道一个技巧就是如何截取从最大串到最小串的判断。时间复杂度是O(N^3)

class Solution {
    public String longestPalindrome(String s) {

        //O(N^3)的时间复杂度
        if(s.length() <= 1)
            return s;
        for(int i = s.length(); i >= 0; i--)
        {
            for(int j = 0; j <= s.length() - i; j++)
            {
                //关键在于这个截取的子串,由长到短,这个是最关键的
                String subStr = s.substring(j, i+j);//从外向内收缩的子串,截取的子串越来越短
                int count = 0;
                for(int k = 0; k < subStr.length()/2; k++)
                {
                    if(subStr.charAt(k) == subStr.charAt(subStr.length() - k -1))//判断是不是回文
                        count++;
                }
                 if(count == subStr.length() / 2)//第一次出现的回文就是最长的
                     return subStr;
            }
           
        }
        return "";
        }
 } 

思路二:马拉车算法,时间复杂度为O(N),具体算法过程看这里:Manacher’s Algorithm 马拉车算法
马拉车的算法核心就是以当前节点为中心点,求当前这个点的最大回文串。而关键的步骤就是如何加快这个扩散。
马拉车算法分为两大部分:
1、当前节点i在右边界mx外,直接暴力扩散
2、当前节点i在右边界内:
(1)i的对称点i在最大左右边界L内,则i的回文串长度为i的回文串长度
(2)i的对称点i在最大左右边界L外,则i的回文串长度为到R的距离。
(3)i的对称点i
在最大左右边界L上,则i的回文串要计算R之后的那部分是否是回文串

class Solution {
    public String longestPalindrome(String s) {
        //马拉车算法O(N)的时间复杂度
        if(s.length()==0)
            return "";
        StringBuilder t = new StringBuilder("$#");
        for(int i = 0; i < s.length(); i++)
        {
            t.append(s.charAt(i));
            t.append('#');
        }
        t.append('@');
        int[] p = new int[t.length()];
        int mx = 0;
        int id = 0;
        int resLen = 0;
        int resCenter = 0;
        for(int i = 1; i < t.length()-1; ++i)
        {
        	//关键算法步骤,mx > i表示当前点在右边界内还是外?如果是外,则重新开始扩散也就是等于1,
        	//当在右边界里面的时候,则判断对称点i*半径有没有超过左边界,判断两者拿个比较短,就是哪个。
        	//p[2 * id - i]表示没有超过的长度,mx-i表示超出的时候的长度
            p[i] = mx > i ? Math.min(p[2 * id - i], mx - i) : 1;
            //如果对称点的长度比当前的还长,后面的是否匹配要自己去算
            while (((i - p[i])>=0) && ((i + p[i])<t.length()-1) 
            		&& (t.charAt(i + p[i]) == t.charAt(i - p[i])))
            		 			++p[i];
            if (mx - i <  p[i]) {
                mx = i + p[i];
                id = i;
            }
            if (resLen < p[i]) {
                resLen = p[i];
                resCenter = i;
                }   
        }
        
        return s.substring((resCenter - resLen) / 2,(resCenter - resLen) / 2 + resLen - 1);
    }
}

你可能感兴趣的:(LeetCode中等难度刷题)