Leetcode | Palindrome
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.
处理好大小写转换、非法字符忽略就可以。
1 class Solution { 2 public: 3 4 bool isPalindrome(string s) { 5 if (s.empty()) return true; 6 int l = 0, r = s.length() - 1; 7 char c1, c2; 8 while (r > l) { 9 while (true) { 10 if (l >= r) break; 11 if (s[l] >= 'a' && s[l] <= 'z') break; 12 if (s[l] >= 'A' && s[l] <= 'Z') { s[l] += 32; break; } 13 if (s[l] >= '0' && s[l] <= '9') break; 14 l++; 15 } 16 17 while (true) { 18 if (l >= r) break; 19 if (s[r] >= 'a' && s[r] <= 'z') break; 20 if (s[r] >= 'A' && s[r] <= 'Z') { s[r] += 32; break; } 21 if (s[r] >= '0' && s[r] <= '9') break; 22 r--; 23 } 24 25 if (s[l] != s[r]) return false; 26 l++; r--; 27 } 28 29 return true; 30 } 31 };
这样写好一点。
1 class Solution { 2 public: 3 bool isDigit(char c) { 4 return (c >= '0' && c <= '9'); 5 } 6 7 bool isUppercase(char c) { 8 return (c >= 'A' && c <= 'Z'); 9 } 10 11 bool isLowercase(char c) { 12 return (c >= 'a' && c <= 'z'); 13 } 14 15 bool isValid(char c) { 16 return (isLowercase(c) || isDigit(c) || isUppercase(c)); 17 } 18 19 bool isPalindrome(string s) { 20 if (s.empty()) return true; 21 int n = s.length(); 22 for (int i = 0, j = n - 1; i < j; ) { 23 for (; i < j && !isValid(s[i]); i++); 24 for (; i < j && !isValid(s[j]); j--); 25 if (isUppercase(s[i])) s[i] += 32; 26 if (isUppercase(s[j])) s[j] += 32; 27 if (s[i] != s[j]) return false; 28 i++, j--; 29 } 30 return true; 31 } 32 };
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"]
]
回溯法就可以了。
1 class Solution { 2 public: 3 4 bool isPalindrome(string &s) { 5 int n = s.length(); 6 if (n <= 1) return true; 7 int l = 0, r = n - 1; 8 while (r > l) { 9 if (s[l] != s[r]) return false; 10 r--; l++; 11 } 12 return true; 13 } 14 15 vector<vector<string>> partition(string s) { 16 vector<vector<string>> rets; 17 18 vector<string> ret; 19 bt(s, 0, ret, rets); 20 21 return rets; 22 } 23 24 void bt(string &s, int index, vector<string> &ret, vector<vector<string>> &rets) { 25 if (index >= s.length()) { 26 rets.push_back(ret); 27 return; 28 } 29 30 for (int i = index; i < s.length(); ++i) { 31 string tmp(s.substr(index, i - index + 1)); 32 if (isPalindrome(tmp)) { 33 ret.push_back(tmp); 34 bt(s, i + 1, ret, rets); 35 ret.pop_back(); 36 } 37 } 38 } 39 };
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.
这里主要有两层需要dp的。
1. 令p[i][j]为i到j之间需要的最小cut个数。我们要求的是p[0][n - 1]。第一个dp很简单,p[i][n - 1] = min{p[j+1][n-1]} + 1, 其中i<=j<n,s(i, j)是回文。
2. 判断回文其实也是一个dp的过程,不过每次都用循环。如果s(i, j)是回文,则p[i][j]=0。p[i][j] = 0 当且仅当str[i]== str[j] && p[i + 1][j - 1]=0。没有这一部分dp就会TLE了。这一步骤用递归就可以,注意的是,比较后要设置p[i][j],无论是否等于0.
1 class Solution { 2 public: 3 bool isPalindrome(string &s, int l, int r, vector<vector<int> > &p) { 4 if (l > r) return true; 5 if (p[l][r] == 0) return true; 6 if (p[l][r] != -1) return false; 7 if (s[l] != s[r]) return false; 8 9 bool isPalin = isPalindrome(s, l + 1, r - 1, p); 10 if (isPalin) { 11 p[l][r] = 0; 12 } else { 13 p[l][r] = r - l; 14 } 15 return isPalin; 16 } 17 18 int minCut(string s) { 19 int n = s.length(); 20 if (n <= 1) return 0; 21 vector<vector<int> > p(n, vector<int>(n, -1)); 22 for (int i = 0; i < n; ++i) { 23 p[i][i] = 0; 24 } 25 for (int i = n - 2; i >= 0; --i) { 26 p[i][n - 1] = n - i - 1; 27 for (int j = i; j < n; ++j) { 28 if (s[j] == s[i] && isPalindrome(s, i + 1, j - 1, p)) { 29 p[i][j] = 0; 30 31 if (j < n - 1 && p[j + 1][n - 1] + 1 < p[i][n - 1]) { 32 p[i][n - 1] = p[j + 1][n - 1] + 1; 33 } 34 } 35 } 36 } 37 38 return p[0][n - 1]; 39 } 40 };
第三次写,用了两个数组。不过思路也算简单了。
1 class Solution { 2 public: 3 int minCut(string s) { 4 if (s.empty()) return 0; 5 int n = s.length(); 6 vector<vector<bool> > dp(n, vector<bool>(n, false)); 7 vector<int> min(n, 0); 8 for (int i = 1; i < n; ++i) { 9 dp[i][i] = true; 10 min[i] = min[i - 1] + 1; 11 for (int j = i - 1; j >= 0; --j) { 12 if ((j > i - 2 || dp[j + 1][i - 1]) && s[i] == s[j]) { 13 dp[j][i] = true; 14 if (j == 0) min[i] = 0; 15 else if (min[j - 1] + 1 < min[i]) min[i] = min[j - 1] + 1; 16 } 17 } 18 } 19 return min[n - 1]; 20 } 21 };
空间上比起用vector<vector<int> >还是省了。因为用bool的话,最终用了O(n^2+n),用int虽然看起来只用了一个变量,但是却是O(4n^2)。