zoukankan      html  css  js  c++  java
  • 【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;
                    }
                }
            }
        }
  • 相关阅读:
    POJ2104&&HDU2665(静态区间第K小)
    HDU4763
    js 获取视频的第一帧
    hadoop 集群配置
    redis_cli 批量删除
    vmware centos 7 更新vmware-tools
    php计算两个整数的最大公约数常用算法小结
    centOS 7 配置NAT模式
    centOS配置NAT模式
    show table status 获取表的信息
  • 原文地址:https://www.cnblogs.com/dplearning/p/4526435.html
Copyright © 2011-2022 走看看