题目
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例:
输入: “aab”
输出: [ [“aa”,“b”], [“a”,“a”,“b”] ]
解答
思路
回溯
- 如果要找出所有的回文串,那么可以从当前的位置依次进行切分判断,之后将满足的进行归纳。但是毫无疑问,这种暴力法不提倡。
- 对以上进行改进,如果当前的字串已经不是回文,那么在其之后的划分已经没必要,所以可以进行建筑。
- 对每一种路径,保存当前的划分结果,当达到停止条件时,进行最后的返回
动态规划
- 如果按照以上操作进行,那么会出现很多重复的判断,从而造成浪费。因此,可以提前初始化二维容器,将每一段字串是否为回文进行记录。当进行回溯时,提升速度。
- 动态规划表达式,如果i=j,则表示为同一个字符,为回文;如果j-i=1,则为两个字符,需要判断是否相同;如果j-i>1,则为三个及以上字符,需要判断i+1至j-1的字串是否为回文以及当前i字符与j字符相同。因此,可以将后两种进行合并,最后表达式如下图。
图解
代码
class Solution {
private:
vector<vector<int>> f;
vector<vector<string>> ret;
vector<string> ans;
int n;
public:
void dfs(const string& s,int i)//传入总的字符串,以及当前执行层数
{
if(i==n) //如果已经执行到最后一个
{
ret.push_back(ans); //将当前结果加入到答案容器中,并且结束
return;
}
for(int j=i;j<n;++j) //如果不是,则继续选择分支(一层中的不同分支),广度优先
{
if(f[i][j]) //如果当前的字串为回文,则保留结果,并且继续循环
{
ans.push_back(s.substr(i,j-i+1)); //保存当前的回文字传
dfs(s,j+1); //继续下一层的循环查找
ans.pop_back(); //移除,便于重新回溯
}
}
}
vector<vector<string>> partition(string s) {
n = s.size(); //获取当前字符串的数量
f.assign(n,vector<int>(n,true)); //赋值函数,不同容器但相容的赋值
for(int i=n-1;i>=0;--i) //横坐标从后开始迭代
{
for(int j=i+1;j<n;++j) //纵坐标从当前的前一位进行动态规划
{
f[i][j] = (s[i]==s[j])&&f[i+1][j-1];
}
}
dfs(s,0);
return ret;
}
};
知识点
回溯框架
- 选择
- 约束条件
- 目标格式
动态规划框架
- 递推式
- 初始条件
- 目标格式
assgin()函数
可以对不同容器但是样式相同进行赋值