横向表示从某个下标开始不断截取不同长度的字符串,直到将字符串截取完
纵向是当前截取了当前字符串后,继续截取剩余字符串
从根节点到叶子节点的路径,就组成了分割结果
class Solution {
public:
vector<vector<string>> ans;
vector<string> path;
bool isPalindrome(string s){
int l = 0;
int r = s.size() - 1;
while(l < r){
if(s[l] != s[r]){
return false;
}
l++;
r--;
}
return true;
}
void func(int startIndex, const string& s){
if(startIndex == s.size()){
ans.push_back(path);
}
// n表示截取的长度
// for循环横向遍历,从startIndex开始,不断截取,直到讲s截取完
for(int n = 1; n <= s.size() - startIndex; n++){
string subs = s.substr(startIndex, n);
if(!isPalindrome(subs)){
continue;
}
path.push_back(subs);
func(startIndex + n, s); // 截取了多少个字符,起始的下标就后移多少
path.pop_back();
}
}
vector<vector<string>> partition(string s) {
func(0, s);
return ans;
}
};
算法优化:先用dp算出所有子串是否是回文串,就不用频繁调用函数判断当前子串是否是回文串了
class Solution {
public:
vector<vector<string>> ans;
vector<string> path;
void func(int startIndex, const string& s, const vector<vector<bool>>& isPalindrome){
if(startIndex == s.size()){
ans.push_back(path);
}
// n表示截取的长度
// for循环横向遍历,从startIndex开始,不断截取,直到讲s截取完
for(int n = 1; n <= s.size() - startIndex; n++){
string subs = s.substr(startIndex, n);
if(!isPalindrome[startIndex][startIndex + n - 1]){
continue;
}
path.push_back(subs);
func(startIndex + n, s, isPalindrome); // 截取了多少个字符,起始的下标就后移多少
path.pop_back();
}
}
vector<vector<string>> partition(string s) {
int len = s.size();
vector<vector<bool>> isPalindrome(len, vector<bool>(len, false));
for(int r = 0; r < len; r++){
for(int l = 0; l <= r; l++){
// 在两端字符相同的情况下,若中间间隔字符不超过1个,那就是回文串了
// 在两端字符相同的情况下,若中间间隔字符超过1个,还需要判断内侧字符是否是回文串
if(s[l] == s[r] && (r - l <= 2 || isPalindrome[l+1][r-1])){
isPalindrome[l][r] = true;
}
}
}
func(0, s, isPalindrome);
return ans;
}
};