【LeetCode】214. Shortest Palindrome


Shortest Palindrome

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".

Credits:
Special thanks to @ifanchu for adding this problem and creating all test cases. Thanks to @Freezen for additional test cases.

 

這題比較直觀的解法是,尋找s中以s[0]為起始的最長回文子串pres(因此是從s的尾部往前遍歷,判斷是回文即返回),

即后續部分為sufs,然后只需要在s之前補全reverse_sufs的逆轉即可。

這樣的話reverse_sufs與sufs對稱,pres自己與自己對稱,肯定是最短回文串。

最壞復雜度為O(n^2),n為s中字符個數。

然而被某個奇葩的測試用例超時了。

先貼出來吧,個人認為面試的十分鍾內能寫出這個已經可以pass了。

后文再貼標准做法。

class Solution {
public:
    string shortestPalindrome(string s) {
        if(s == "")
            return s;
        int i = s.size()-1;
        while(i >= 0)
        {
            // spre is s[0,...,i]
            string spre = s.substr(0, i+1);
            if(isPalin(spre))
                break;
            i --;
        }
        string pre = s.substr(i+1);
        reverse(pre.begin(), pre.end());
        return pre + s;
    }
    bool isPalin(string s)
    {
        for(int i = 0, j = s.size()-1; i < j; i ++, j --)
        {
            if(s[i] != s[j])
                return false;
        }
        return true;
    }
};

 

首先確認一點基本知識,如果某個字符串str是回文的,那么str == reverse(str)

因此,將s逆轉之后拼接在s后面,即news=s+reverse(s),該新字符串news首尾相同的部分,即為s中以s[0]為起始的最長回文子串pres

只不過這里我不用上述的遍歷來做,而用類似KMP算法求next數組來做。

在KMP算法中求next數組就是s自我匹配的過程,next[i]的值就表示s[i]之前有幾個元素是與s開頭元素相同的。

因此,next[news.size()]的值就表示news中首尾相同的部分的長度。接下來就好做了。

注意:當next[news.size()]的值大於s.size()時,說明重復部分貫穿了s與reverse(s),應該修正為next[news.size()]+1-s.size()

class Solution {
public:
    string shortestPalindrome(string s) {
        if(s == "")
            return s;
        string s2 = s;
        reverse(s2.begin(), s2.end());
        string news = s + s2;
        int n = news.size();
        vector<int> next(n+1);
        buildNext(news, next, n);
        if(next[n] > s.size())
            next[n] = next[n] + 1 - s.size();
        string pres = s.substr(next[n]);
        reverse(pres.begin(), pres.end());
        return pres + s;
    }
    void buildNext(string& s, vector<int>& next, int n)
    {
        int k = -1;
        int j = 0;
        next[0] = -1;
        while(j < n)
        {
            if(k == -1 || s[j] == s[k])
            {
                k ++;
                j ++;
                next[j] = k;
            }
            else
            {
                k = next[k];
            }
        }
    }
};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM