leetcode原题链接:分割回文串
上一篇:HOT60-单词搜索
下一篇:HOT62-N皇后
题目描述
给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是 回文串 。返回 s
所有可能的分割方案。回文串 是正着读和反着读都一样的字符串。
示例 1:
输入:s = "aab" 输出:[["a","a","b"],["aa","b"]]
示例 2:
输入:s = "a" 输出:[["a"]]
提示:
1 <= s.length <= 16
s
仅由小写英文字母组成
解题方法: 回溯法。定义backtrack(s, i, tmp, result)表示以i为当前分割的起点,从[i, n)中获取回文串。然后遍历不同的j=i+len,如果[i,j]是回文串,则下一段查找从j+1开始,详细见代码注释。另外,值得一提的是如何判断s[i...j]是否为回文串,方法如下:
方法1: 双指针法(在本题中的缺陷是有重复计算)
方法2: 动态规划法。dp[i][j]表示str[i...j]是否为回文串
dp[i-1][j+1] = dp[i][j] && s[i-1]==s[j+1]
从左右等号两边的i,j关系可以看出,二维数组初始化遍历的顺序i是从大到下,j是从小到大。
C++代码
#include <iostream>
#include <vector>
#include <string>
/*
abcb
方法1: 双指针法(在本题中的缺陷是有重复计算)
方法2: 动态规划法。dp[i][j]表示str[i...j]是否为回文串
dp[i-1][j+1] = dp[i][j] && s[i-1]==s[j+1]
*/
class Solution {
public:
std::vector<std::vector<std::string>> partition(std::string s) {
std::vector<std::string> tmp;
std::vector<std::vector<std::string>> result;
backtrack(s, 0, tmp, result);
return result;
}
void backtrack(const std::string& s,
int i,
std::vector<std::string>& tmp,
std::vector<std::vector<std::string>>& result) { //以i为起点
int n = s.size();
if (i == n) {
result.emplace_back(tmp);
}
for (int j = i; j < n; j++) {
int len = j - i + 1; // [i, ..., j]
if (check(s, i, j)) { // 判断 [i, j]是否为回文串
tmp.push_back(s.substr(i, len)); // 选择[i...j]
backtrack(s, j + 1, tmp, result); //继续从j的下一个位置开始选择
tmp.pop_back(); //撤销选择
}
}
}
// 判断s[i,...,j]是否为回文串,这里用的是最朴素的方法。
// 当然可以用动态规划优化,可以减少重复计算:
// 动态规划优化的方法是用dp[i][j]保存s[i,...,j]是否为回文串
// 状态转移方程:dp[i-1][j+1] = dp[i][j] && s[i-1]==s[j+1]
// 初始化顺序:i从大到小,j从小到大 (根据等号两边i,j的大小可以看出)
bool check(const std::string& s, int i, int j) {
while (i <= j) {
if (s[i] != s[j]) {
return false;
}
i++;
j--;
}
return true;
}
};