题目: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