欢迎访问LeetCode题解合集
题目描述
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例:
输入: "aab"
输出:
[
["aa","b"],
["a","a","b"]
]
题解:
法一:
枚举所有可能的分割点,然后判断分割点组成的子串是否是回文串即可。
这里枚举分割点可以二进制枚举子集,但需要注意,必须包含最后一个位置。
时间复杂度:$O(n * 2^n)$
额外空间复杂度:$O(n)$
class Solution {
public:
bool isPalind( const string& s ) {
for ( int i = 0, j = s.size() - 1; i < j; ++i, --j )
if ( s[i] != s[j] ) return false;
return true;
}
vector<vector<string>> partition(string s) {
int n = s.length();
vector<int> idx;
vector<string> ans;
vector<vector<string>> ret;
string t;
int pre;
bool flag;
for ( int i = 1 << ( n - 1 ); i < 1 << n; ++i ) {
idx.clear();
for ( int j = 0; j < n; ++j ) {
if ( i >> j & 1 ) idx.emplace_back( j );
}
pre = 0;
flag = true;
ans.clear();
for( const auto& it : idx ) {
t = s.substr( pre, it - pre + 1 );
if ( !isPalind( t ) ) {
flag = false;
break;
}
pre = it + 1;
ans.emplace_back( move(t) );
}
if ( flag ) ret.emplace_back( move(ans) );
}
return ret;
}
};
/*
时间:180ms,击败:52.32%
内存:89.8MB,击败:14.09%
*/
法二:
回溯。
递归过程中维护回文子串的起始位置,然后枚举回文子串所有可能的结束位置。
时间复杂度:$O(n * 2 ^n)$
额外空间复杂度:$O(n)$
class Solution {
public:
vector<vector<string>> ret;
vector<string> path;
bool isPalind( const string& s ) {
for ( int i = 0, j = s.size() - 1; i < j; ++i, --j )
if ( s[i] != s[j] ) return false;
return true;
}
void dfs( int st, const string& s ) {
if ( st >= s.size() ) {
ret.emplace_back( path );
return;
}
string t;
for ( int i = st; i < s.size(); ++i ) {
t = s.substr( st, i - st + 1 );
if ( !isPalind( t ) ) continue;
path.emplace_back( t );
dfs( i + 1, s );
path.pop_back();
}
}
vector<vector<string>> partition(string s) {
dfs( 0, s );
return ret;
}
};
/*
时间:136ms,击败:74.31%
内存:73.9MB,击败:62.49%
*/
法三:
可以发现,无论是 方法一 还是 方法二 ,均有一个判断子串是否是 回文串 的过程,这个过程的时间复杂度为 $O(n)$,并且在递归或枚举过程中,会产生大量重复判断。可以提前预处理判断 s[i...j]
是否是回文串,然后直接 $O(1)$ 判断。
时间复杂度:$O(n * 2^n)$
额外空间复杂度:$O(n ^ 2)$
class Solution {
public:
vector<vector<string>> ret;
vector<string> path;
vector<vector<bool>> f;
void dfs( int st, const string& s ) {
if ( st >= s.size() ) {
ret.emplace_back( path );
return;
}
for ( int i = st; i < s.size(); ++i ) {
if ( !f[st][i] ) continue;
path.emplace_back( move(s.substr(st, i - st + 1)) );
dfs( i + 1, s );
path.pop_back();
}
}
vector<vector<string>> partition(string s) {
int n = s.size();
f = vector<vector<bool>> ( n, vector<bool>(n) );
f[0][0] = true;
for ( int i = 1; i < n; ++i ) {
f[i][i] = true;
f[i - 1][i] = (s[i - 1] == s[i]);
}
for ( int l = 3; l <= n; ++l ) {
for ( int i = 0, j; i + l - 1 < n; ++i ) {
j = i + l - 1;
if ( s[i] == s[j] ) f[i][j] = f[i + 1][j - 1];
else f[i][j] = false;
}
}
dfs( 0, s );
return ret;
}
};
/*
时间:140ms,击败:72.00%
内存:74MB,击败:58.26%
*/
好像没有什么优化效果。。。