首先是经典的最长回文子串,Manacher给出了线性的算法。
Longest Palindromic Substring
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000,
and there exists one unique longest palindromic substring.
class Solution {
public:
string longestPalindrome(string s) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
//use Manacher's Algorithm O(n)
if(s.empty()) return s;
int len = s.length();
int i;
//construct new string
ostringstream ss;
ss << "^";
for(i = 0; i < len; ++i){
ss<<"#"<<s[i];
}
ss<<"#$";
string newstr = ss.str();
len = newstr.length();
vector<int> p(len,1);
int mx(0),id(0),ans(1),center(0);
for(i = 1; i < len-1; ++i){
p[i] = (mx > i) ? min(p[2 * id - i], mx - i) : 1;
while(newstr[i - p[i]] == newstr[i + p[i]]) p[i]++;
if(i + p[i] > mx){//update mx and id
mx = i + p[i];
id = i;
}
if(p[i] > ans){//update ans and center
center = i;
ans = p[i];
}
}
ans -= 1;
return s.substr((center - ans - 1) / 2, ans);
}
};
Valid Palindrome
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
For example,
"A man, a plan, a canal: Panama"
is a palindrome.
"race a car"
is not a palindrome.
Note:
Have you consider that the string might be empty? This is a good question to ask during an interview.
For the purpose of this problem, we define empty string as valid palindrome.
class Solution {
public:
bool isPalindrome(string s) {
// Note: The Solution object is instantiated only once and is reused by each test case.
/*
if(s.empty()) return true;
stringstream ss;
for(int i = 0; i < s.length(); ++i){
if(isdigit(s[i]))
ss<<s[i];
else if(isupper(s[i])){
ss<<char(s[i]+32);
}
else if(islower(s[i])){
ss<<s[i];
}
}
string cleanstr = ss.str();
int len = cleanstr.length();
if(0 == len)
return true;
int left = 0, right = len -1;
while(left < right){
if(cleanstr[left++] != cleanstr[right--])
return false;
}
return true;
*/
//don't use extra string space
if(s.empty()) return true;
int len = s.length();
int i(0), j(len-1);
while( i < j){
if(!isalnum(s[i])) ++i;
else if(!isalnum(s[j])) --j;
else{
if(isupper(s[i])) s[i] += 32;
if(isupper(s[j])) s[j] += 32;
if(s[i] != s[j]) return false;
++i;--j;
}
}
return true;
}
};
Palindrome Number
Determine whether an integer is a palindrome. Do this without extra space.
Could negative integers be palindromes? (ie, -1)
If you are thinking of converting the integer to string, note the restriction of using extra space.
You could also try reversing an integer. However, if you have solved the problem "Reverse Integer", you know that the reversed integer might overflow. How would you handle such case?
There is a more generic way of solving this problem.
class Solution {
public:
bool isPalindrome(int x) {
// Note: The Solution object is instantiated only once and is reused by each test case.
if(x < 0) return false;
int div = 1;
while(x / div >= 10)
div *= 10;
while(x){
int l = x /div;
int r = x % 10;
if(l != r) return false;
x = (x % div) / 10;
div /= 100;
}
return true;
}
};
Palindrome Partitioning
Given a string s, partition s such that every substring of the partition is a palindrome.
Return all possible palindrome partitioning of s.
For example, given s = "aab"
,
Return
[ ["aa","b"], ["a","a","b"] ]
这个题对时间的限制要求在判断是否是回文串的时候打个表记录一下,否则会超时。
用dp的思路去打表求ispa[i][j] , 然后用回溯得到所有可能的解。
class Solution {
public:
vector<vector<string>> partition(string s) {
// Note: The Solution object is instantiated only once and is reused by each test case.
int len = s.length();
if(0 == len) return vector<vector<string> >();
vector<vector<bool> > ispa(len,vector<bool>(len,false));
//build ispa with DP
for(int i = 1; i <= len; ++i){
for(int j = 0; j + i -1 < len; ++j){
int k = j + i - 1;
if(1 == i) ispa[j][j] = true;
else if(2 == i) ispa[j][k] = (s[j] == s[k]);
else
ispa[j][k] = ( s[j] == s[k] && ispa[j+1][k-1] );
}
}
//backtracking to get solution
vector<string> tmp;
vector<vector<string> > ret;
helper(s,0,tmp,ret,ispa);
return ret;
}
void helper(const string &s, int pos, vector<string> &solution, vector<vector<string> > &result,const vector<vector<bool> > &ispa){
if(pos == s.length()){
result.push_back(solution);
return;
}
for(int i = pos; i < s.length(); ++i){
if(ispa[pos][i]){
solution.push_back(s.substr(pos,i-pos+1));
helper(s,i+1,solution,result,ispa);
solution.pop_back();
}
}
return;
}
};
Palindrome Partitioning II
Given a string s, partition s such that every substring of the partition is a palindrome.
Return the minimum cuts needed for a palindrome partitioning of s.
For example, given s = "aab"
,
Return 1
since the palindrome partitioning ["aa","b"]
could be produced using 1 cut.
而且代码可以如此的精简。
class Solution {
public:
int minCut(string s) {
// Note: The Solution object is instantiated only once and is reused by each test case.
/* TLE because of bfs
//DP for calculating ispa and bfs for calculating result (TLE Yunk)
int len = s.length();
if(0 == len) return 0;
vector<vector<bool> > ispa(len,vector<bool>(len,false));
//build ispa with DP
for(int i = 1; i <= len; ++i){
for(int j = 0; j + i - 1 < len; ++j){
int k = j + i - 1;
if(1 == i) ispa[j][j] = true;
else if(2 == i) ispa[j][k] = (s[j] == s[k]);
else
ispa[j][k] = (s[j] == s[k] && ispa[j+1][k-1]);
}
}
//calculate min cut
//bfs from back to front
queue<pair<int,int> > que;
que.push(make_pair(len-1,0));
while(!que.empty()){
pair<int,int> p = que.front();
que.pop();
int id = p.first;
int step = p.second;
for(int j = 0; j <= id; ++j){
if(ispa[j][id]){
if(j == 0){//can get final point
return step;
}
que.push(make_pair(j-1,step+1));
}
}
}
return -1;
*/
//use dp to calculate mincut
//dp[i] = min{ dp[j+1]+1 | j >= i && ispa[i][j] == true}
//from back to front ,result is dp[0] - 1
int len = s.length();
if(0 == len) return 0;
vector<vector<bool> > ispa(len,vector<bool>(len,false));
vector<int> dp(len+1);
dp[len] = 0;
for(int i = len-1; i >= 0; --i ){
dp[i] = len - i;
for(int j = i ; j < len; ++j){
if(s[i] == s[j] && (j - i < 2 || ispa[i+1][j-1])){
ispa[i][j] = true;
dp[i] = min(dp[i], dp[j+1] + 1 );
}
}
}
return dp[0]-1;
}
};