Leetcode0005--Longest Palindromic Substring 最长回文串

【转载请注明】http://www.cnblogs.com/igoslly/p/8726771.html

 

来看一下题目:

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

Example:

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

Example:

Input: "cbbd"   Output: "bb"

题目意思:

   给出字符串中最长的回文串

   若长度相同,给出位置最前

作为较经典的题目,回文串通常有几种方法,已经有很多人分析过了,提供链接:https://segmentfault.com/a/1190000005063336

总的来说:

1、穷举法

      对于长度为 n 的字符串,有字符串 n(n+1)/2 ,判断是否回文串复杂度为 O(n),算法整体复杂度为 O(n^3)

2、中心扩展法

    对于回文串,从对称轴展开的字符均相同;把字符串的每个位置作为回文串的对称轴,判断回文串的最大长度;子串对称轴遍历复杂度为O(n),回文判断O(n)

    这里要注意:长度为奇数 / 偶数时,对称轴的位置不同

class Solution {
public:
    int max=0;
    string res="";
    string longestPalindrome(string s) {
        if(s.size()==1){return s;}
        int len=s.size();
        for(int i=0;i<len-1;i++){
            // 字符串从0 ~ len-2位置,i&i进行奇数判断,i&i+1进行偶数判断
            check(s,i,i);
            check(s,i,i+1);
        }
        return res;
    }
    // 判断回文串最大长度
    void check(string s,int i,int j){
        while(i>=0&&j<s.size()){
            // 若两边扩展字符相等,更新最大长度
            if(s[i]==s[j]){
                if(j-i+1>max){
                    max=j-i+1;
                    res=s.substr(i,max);
                }
                i--;
                j++;
            }else{
                return;
            }
        }
    }
};

        给出一个Leetcode大神的代码,也是以中心扩展法为基本思想

class Solution {
public:
    string longestPalindrome(string s) {
        // 去除长度为0、1情况
        if (s.empty()) return "";
        if (s.size() == 1) return s;
        // 记录最长回文串的起始位置、最大长度
        int min_start = 0, max_len = 1;
        for (int i = 0; i < s.size();) {
            if (s.size() - i <= max_len / 2) break;
            int j = i, k = i;   // 以i作为中心位置,进行两边扩展
            // 若中心毗邻字符串,则直接包含在内;因为中心位置相同字母必然对称
            while (k < s.size()-1 && s[k+1] == s[k]) ++k; // Skip duplicate characters.
            i = k+1;
            // 以j,k向两边扩展,进行比较更新
            while (k < s.size()-1 && j > 0 && s[k + 1] == s[j - 1]) { ++k; --j; } // Expand.
            int new_len = k - j + 1;
            if (new_len > max_len) { min_start = j; max_len = new_len; }
        }
        return s.substr(min_start, max_len);
    }
};

3、Manacher算法

      俗称“马拉车算法”,是在中心扩展法的基础上,优化确定最大长度的算法;

      专门设定长度数组(假设为p[len]),记录每个位置的最大长度;

      为了避免长度奇偶问题,在原字符串的中间,插入‘#’异常符号

举个例子:

s="abbahopxpo"

转换为

s_new="$#a#b#b#a#h#o#p#x#p#o#"

     有较为形象具体的说明:https://segmentfault.com/a/1190000008484167

实现代码:

string add_string(string s){
    string news="$#";
    int len=s.size();
    int j=2;
    for(int i=0;i<len;i++){
        news+=s[i];
        news+='#';
    }
    return news;
}
class Solution {
public:
    string longestPalindrome(string s) {
        s=add_string(s);
        int len=s.size(),maxlen=-1;
        int id,mx=0,p[len],maxindex;
        for(int i=1;i<len;i++){
            if(i<mx) {p[i]=min(p[2*id-i],mx-i);
            }else{p[i]=1;}
            
            while(s[i-p[i]]==s[i+p[i]]) p[i]++;
            if(mx<i+p[i]){
                id=i;
                mx=i+p[i];
            }
            if(maxlen<p[i]-1){
                maxlen=p[i]-1;
                maxindex=i;
            }
        }
        string result="";
        for(int i=maxindex-maxlen;i<=maxindex+maxlen;i++){
            if(s[i]!='#'&&s[i]!='$'){
                result+=s[i];
            }
        }
        return result;
    }
};

 

posted @ 2018-04-06 04:05  Arya.Mo  阅读(289)  评论(0编辑  收藏  举报