LeetCode 131. Palindrome Partitioning
给你一个字符串 s,请你将 **s **分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
回文串 是正着读和反着读都一样的字符串。
示例 1:
输入: s = "aab"
输出: [["a","a","b"],["aa","b"]]
示例 2:
输入: s = "a"
输出: [["a"]]
提示:
1 <= s.length <= 16s仅由小写英文字母组成
算法
dfs + 回溯
dfs算法的过程其实就是一棵递归树,所有的dfs算法的步骤大概有以下几步:
找到中止条件,即递归树从根节点走到叶子节点时的返回条件,此时一般情况下已经遍历完了从根节点到叶子结点的一条路径,往往就是我们需要存下来的一种合法方案
如果还没有走到底,那么我们需要对当前层的所有可能选择方案进行枚举,加入路径中,然后走向下一层
在枚举过程中,有些情况下需要对不可能走到底的情况进行预判,如果已经知道这条路不可能到达我们想去的地方,那我们干嘛还要一条路走到黑呢,这就是我们常说的剪枝的过程
当完成往下层的递归后,我们需要将当前层的选择状态进行清零,它下去之前是什么样子,我们现在就要让它恢复原状,也叫恢复现场。该过程就是回溯,目的是回到最初选择路口的起点,好再试试其他的路。
将上述思路运用在该题中:
- 从第一个字符开始枚举,用path数组存储一条从递归树根节点到叶子结点的合法方案,用res数组存下所有的合法方案\
- dfs过程的中止条件是当我们遍历完了所有字符,说明我们已经找到一条合法路径,此时将路径加入方案中\
- 然后进行该层的选择枚举,这里枚举从该字符到结尾的所有长度,且该长度的字符串为回文串时,我们将其加入路径中,然后递归到下一层\
- 当我们进行了下层的递归后,我们需要进行回溯,也就是恢复现场,目的是我们能够在该层重新做其他选择
AC代码
class Solution {
public:
vector<vector<string>> res; //所有方案
vector<string> path; //一个合法方案
vector<vector<string>> partition(string s) {
dfs(0, s); //从位置0开始dfs
return res;
}
void dfs(int u, string s)
{
if (u == s.size()) //遍历完整个字符串
{
res.push_back(path); //将路径加入方案
return;
}
for (int i = u; i < s.size(); i ++) //枚举从当前字符到结尾可以选择的长度
{
if (check(s, u, i)) //判断u ~ i是否为回文串
{
path.push_back(s.substr(u, i - u + 1)); //加入路径
dfs(i + 1, s); //递归下一层
path.pop_back(); //回溯
}
}
}
bool check(string s, int l, int r) //判断从l到r是否为回文串
{
while (l <= r)
{
if (s[l ++] != s[r --])
return false;
}
return true;
}
};