【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;

                }

            }

        }

    }

 

你可能感兴趣的:(LeetCode)