【leetcode】Shortest Palindrome(hard)★

Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.

For example:

Given "aacecaaa", return "aaacecaaa".

Given "abcd", return "dcbabcd".

 

思路:

写了三份代码,各种超时。知道肯定要用之前学了几遍也记不住的方法了--判断最长回文的O(N)算法Manacher算法。

特别注意:

s[i]这样的写法非常耗时!

    //Manacher算法
    string shortestPalindrome(string s){
        if(s.size() <= 1) return s;
        string ss = "$#";
        for(auto c : s)  //这样写只需要12ms
            ss+=c, ss+='#';
        //for(int i = 0; i < s.size(); ++i) //先把字符串转换一下  这样写非常慢 240ms时间都耗在这里了 
        //    ss = ss + s[i] + "#";
        
        vector<int> P(2 * s.size() + 2, 0); //存储以i为中心回文的最大半径
        int e = 0;
        int id = 1, mx = 0; //id为可以管的最远的回文的中心点 mx是id可以管到的最远距离 在回文的后面一个位置
        for(int i = 1; i < ss.size(); ++i)
        {
            P[i] = (mx > i) ? min(P[2 * id - i], mx - i) : 1;  //根据之前的信息 获取当前中心点的最短回文长度
            while(i + P[i] < ss.size() && ss[i + P[i]] == ss[i - P[i]]) //扩展回文长度 注意不要越界
                P[i]++;
            if(i + P[i] > mx)  //更新最远距离和中心点
            {
                mx = i + P[i];
                id = i;
            }
            if(i == P[i]) e = i + P[i] - 1; //该回文的第一个位置是源字符串的第一个字母 记录回文截至位置
        }
        e = e / 2 - 1; //把回文最长的截至位置转换为在原字符串中的位置
        string rs = s.substr(e + 1, s.size() - e); //在字符串前面补上不够回文的部分
        reverse(rs.begin(), rs.end());
        return rs + s;
    }

大神4ms的代码,其实思路都一样,可大神的代码时间就是短!

string shortestPalindrome(string s) {
    int n1=s.length();
    string mystr="$";//2*n1+1
    int n=2*n1+1;
    for(auto c : s)
        mystr+=c, mystr+='$';
    int* plen=new int[n];
    int pali_len=1;
    int i, k, mid=0, l=-1;
    for(i=0; i<=n/2; i++)
    {
        k=0;
        if(i<l&&2*mid-i>-1)  k=min(plen[2*mid-i], l-i);
        while(i-k-1>-1&&i+k+1<n&&mystr[i-k-1]==mystr[i+k+1]) k++;
        plen[i]=k;
        if(i+k>l) mid=i, l=i+k;
    }
    for(i=n/2; i>-1; i--)
        if(plen[i]==i)  {pali_len=i; break;}
    string t=s.substr(i);
    reverse(t.begin(), t.end());
    return t+s;
}

 

三个超时的常规思路代码:

bool isPalindrome(string s, int start, int end)
    {
        while(start <= end)
            if(s[start++] != s[end--])
                return false;
        return true;
    }

    //超时
    string shortestPalindrome1(string s) {
        if(s.size() <= 1) return s;
        int e = 0;
        for(int i = s.size() - 1; i >= 0; --i) //找到包括第一个字母的最长回文
        {
            if(isPalindrome(s, 0, i))
            {
                e = i;
                break;
            }
        }

        string rs = s.substr(e + 1, s.size() - e);
        reverse(rs.begin(), rs.end());
        return rs + s;
    }

    //超时
    string shortestPalindrome2(string s){
        if(s.size() <= 1) return s;
        for(int i = s.size() - 1; i >= 0; --i) //遍历可能回文的最后一个位置
        {
            if(s[i] == s[0]) //如果第一个字符和最后位置相同
            {
                int slen = (i + 1) / 2 ; //回文一半的长度  奇数个则不要最中间的
                string s1 = s.substr(0, slen);
                string s2 = s.substr(i - slen + 1, slen);
                reverse(s2.begin(), s2.end());
                if(s1 == s2) //是回文
                {
                    string rs = s.substr(i + 1, s.size() - i);
                    reverse(rs.begin(), rs.end());
                    return rs + s;
                }
            }
        }
    }

    //超时
    string shortestPalindrome3(string s){
        if(s.size() <= 1) return s;
        for(int i = s.size() - 1; i >= 0; --i) //遍历可能回文的最后一个位置
        {
            if(s[i] == s[0]) //如果第一个字符和最后位置相同
            {
                int slen = (i + 1) / 2 ; //回文一半的长度  奇数个则不要最中间的
                string s1 = s.substr(0, slen);
                string s2 = s.substr(i - slen + 1, slen);
                reverse(s2.begin(), s2.end());
                unordered_set<string> uset;
                uset.insert(s1);
                if(uset.find(s2) != uset.end())
                {
                    string rs = s.substr(i + 1, s.size() - i);
                    reverse(rs.begin(), rs.end());
                    return rs + s;
                }
            }
        }
    }

 

posted @ 2015-05-24 20:49  匡子语  阅读(190)  评论(0编辑  收藏  举报