zoukankan      html  css  js  c++  java
  • 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;
        }
    };

     

  • 相关阅读:
    作用域随笔
    关于取数组地址的识记(&s+1,s+1,&s[0]+1)
    c中关于#与##的简易使用
    Qt Creator的配置
    sizeof对int long double char的使用
    i++与++i的区别
    for循环执行顺序
    gcc 编译的4个过程简单识记
    各进制之间转化识记
    删除临时文件
  • 原文地址:https://www.cnblogs.com/igoslly/p/8726771.html
Copyright © 2011-2022 走看看