[Leetcode] 214. Shortest Palindrome 解题报告

来源:互联网 发布:alpine linux安装字体 编辑:程序博客网 时间:2024/05/16 15:24

题目

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

思路

1、暴力法:我首先想到的就是暴力法,找出字符串s的最长回文前缀,再在字符串的头部加上除去最长回文前缀之外的子字符串的翻转即为所求。这种算法的时间复杂度是O(n!),果然没有通过所有测试数据。

2、KMP记忆法:KMP在我心目中一直是神一样的存在,每次看到之后都觉得很精妙,可是过后就忘了它的具体实现了。这次在网上看到这道题目也可以用KMP记忆法来求解,所以就盗图以及盗文,把KMP记忆法在这里详细解释一下。

KMP的原理是给定一个字符串S和P,要在S中寻找是否存在P,一般的方法是逐位比较,如果不能完全匹配,则S再回到开始位置向右移动一位,P回到0位置再开始比较。在KMP中不需要回到首部重新开始比较,借助与记录从P的开头到当前位置P中的前缀和后缀有多少位是相等的,这样当P和S比较的时候如果P[i] != S[j]了,不需要回到P[0]的位置重新比较,我们可以查看P中已经匹配过的子串中(也就是P[0, i - 1]子串)前缀和后缀有多少位是相等的,然后将P移动到适当的位置。下面盗图说明一下:




所以借助与KMP记录最长前缀和后缀的方法,我们可以将元字符串翻转以后加在原字符串的后面,其最大的前缀和后缀就是前缀的最大回文长度。我们还需要在这两个字符串之间加一个冗余字符,因为形如aaaaa这种字符串如果不加一个冗余字符,则最大前缀和后缀会变大。

代码

1、暴力法:

class Solution {public:    string shortestPalindrome(string s) {        if(s.length() == 0) {            return "";        }        for(int end = s.length() - 1; end >= 0; --end) {            if(isPalindrome(s, 0, end)) {                string added = s.substr(end + 1);                reverse(added.begin(), added.end());                return added + s;            }        }        return "";    }private:    bool isPalindrome(string& s, int start, int end) {        while(start < end) {            if(s[start++] != s[end--]) {                return false;            }        }        return true;    }};

2、KMP记忆法:

class Solution {public:    string shortestPalindrome(string s) {        string str(s);        reverse(str.begin(), str.end());        str = s + "#" + str;        int length1 = s.size(), length2 = str.size();        vector<int> vec(length2, 0);        for (int i = 1; i < length2; ++i) {            int k = vec[i - 1];            while (k > 0 && str[k] != str[i]) {                k = vec[k - 1];            }            vec[i] = (k += str[i] == str[k]);        }        return str.substr(length1 + 1, length1 - vec[length2 - 1]) + s;    }};