题目:Shortest Palindrome

给定字符串,在前面增加最少字符使其组成回文字符串。

思想:

只要找到从字符串头部开始的最长回文子串,就能将剩下的字符串逆置后拼接到前面而得到最短的回文字符串。

/**判断字符串是回文的**/
    bool isPalindrome(string s){
    if (s.size() < 2)return true;
    auto left = s.cbegin();
    auto right = s.cend();
        --right;
        while (left < right){
            while (left != s.cend() && !isalnum(*left))++left;//调过标点等特殊字符
            if (left == s.cend())return true;//串尾
            while (!isalnum(*right))--right;//调过标点等特殊字符
            if ((*left) != (*right))return false;//比较收尾的字符
            ++left;
            --right;
        }
        return true;
    }
    
string LeetCode::shortestPalindrome(string s){
    if (s.size() < 2)return s;
    int tail = s.size();
    while (tail > 1 && !isPalindrome(s.substr(0, tail)))--tail;//找到最长回文子串[0,i]
    if (tail == s.size())return s;//本身就是回文字符串
    string str = s.substr(tail,s.size() - tail);//得到剩余字符串
    reverse(str.begin(),str.end());//逆置
    str.append(s);//拼接
    return str;
}

但是这样时间复杂度是O(n^2)无法通过。

思路:

考虑使用KMP算法。

KMP算法是匹配字符串的一种算法,他用来求字符串中每个字符的最大公共长度,使用next数组保存。

KMP算法可以参照:http://www.cnblogs.com/yeqluofwupheng/p/6797176.html

注意:

拼接的字符串之间添加"#"防止两个字符串连接的地方出现了匹配,是的后面的next数组出错。

这样next数组的最后就表示从0开始的最长回文子串。这样就可以将逆置的字符串的剩余子串拼接到s的前面。

string LeetCode::shortestPalindrome(string s){
    if (s.size() < 2)return s;
    string rev = s;
    reverse(rev.begin(), rev.end());
    string str = s + "#" + rev;
    vector<int>next(str.size(),0);//KMP算法的next数组
    for (size_t i = 1; i < str.size(); ++i){
        int j = next.at(i - 1);//从前一个位置的最大匹配长度开始
        while (j > 0 && str[i] != str[j])j = next.at(j - 1);//如果匹配不成功,则试一试前一个位置(next数组)能否匹配成功
        next[i] = (j += str[i] == str[j]);//如果j减到0,由于数组初始化为0,所以str[i] == str[j]
    }
    return rev.substr(0, s.size() - next.at(str.size() - 1)) + s;
}

其他回文算法:

http://www.cnblogs.com/yeqluofwupheng/p/6720384.html

http://www.cnblogs.com/yeqluofwupheng/p/7341905.html