Given a string s, partition s such that every substring of the partition is a palindrome.
Return all possible palindrome partitioning of s.
Example:
Input: “aab”
Output:
[
[“aa”,“b”],
[“a”,“a”,“b”]
]
method 1 backtracking
patition s 可以看作从左往右,不断往s插入一个分隔符,使得s分为左右两个部分,当left为回文时,接着对right进行递归回溯,插入分隔符
map<string, bool> palindromeMap;
bool isPalindrome(string str){
if (palindromeMap.count(str)) return palindromeMap[str];
bool res = true;
for (int i = 0, j = str.size()-1; i < j; i++, j--)
{
if (str[i] != str[j]){
res = false;
break;
}
}
palindromeMap[str] = res;
return res;
}
void helper(vector<vector<string>>& ans, string part, vector<string> tmp){
if (part == ""){
ans.push_back(tmp);
}
else{
for (int i = 0; i < part.size(); i++)
{
string left = part.substr(0, i + 1);
if (!isPalindrome(left)) continue;
tmp.push_back(left);
string right = part.substr(i + 1, part.size() - (i + 1));
helper(ans, right, tmp);
tmp.pop_back();
}
}
}
method 2 dynamic programming
在回溯过程中,回文串的判断可以引入动态规划
动态规划主要用在了判断字符串是否是回文串上,dp[i][j]代表字符串中从i到j(包括j)是否是回文串,这样判断dp[i][j]是否为回文串主要分为以下三个步骤:
- 如果是一个字符,自然是回文
- 如果是两个字符,判断第一个和第二个是否相等
- 如果是多个字符,那就判断第一个和最后一个是否相等以及中间部分是否相等
void helper2(vector<vector<string>>& ans, string s, vector<string> tmp, int start){
if (start == s.size()){
ans.push_back(tmp);
}else{
for (int i = start; i < s.size(); i++)
{
if (!dp[start][i]){
if (start == i) dp[start][i] = true;
else if (start == i - 1) dp[start][i] = (s[start] == s[i]);
else dp[start][i] = dp[start + 1][i - 1] && s[start] == s[i];
}
if (dp[start][i]){
string left = s.substr(start, i - start+ 1);
tmp.push_back(left);
helper2(ans, s, tmp, i + 1);
tmp.pop_back();
}
}
}
}
vector<vector<string>> partition(string s) {
vector<vector<string>> ans;
if (s.size() == 0) return ans;
dp.resize(s.size(), vector<bool>(s.size(), false));
vector<string> tmp;
helper2(ans, s, tmp, 0);
return ans;
}
summary
- 递归回溯可以看作是从左往右分割的过程,左边是最小符合要求的集合,不需要递归,然后对右边继续递归
- 回文串可以用动态规划进行判断