分割回文串
给定字符串 s, 需要将它分割成一些子串, 使得每个子串都是回文串.最少分割几次?
样例 1:
输入:
"a"
输出:
0
解释: "a" 本身就是回文串, 无需分割
样例 2:
输入:
"aab"
输出:
1
解释: 将 "aab" 分割一次, 得到 "aa" 和 "b", 它们都是回文串.
解答:
定义DP[i][j]为字符串s长度为i时,前j个字符使得每个子串都是回文串并且s的第j+1到第i个字符组成的子串也是回文的最小分割成次数.
则DP[i][j] = DP[j][j]+ 1 其中s[j]->s[i-1]子串是回文的情况下;
否则DP[i][j]不可取,即DP[i][j] = MAX;
取DP[i][i]为DP[i][0]–>DP[i][i-1]的最小值
状态转换方程:
DP[i][j] = DP[j][j]+ 1 {s[j]->s[i-1]子串是回文}
MAX {s[j]->s[i-1]子串不是回文}
min(DP[i][k]) {0<= k < j, i==j}
class Solution {
public:
/**
* @param s: A string
* @return: An integer
*/
int minCut(string &s) {
// write your code here
/*
定义DP[i][j]为字符串s长度为i时,前j个字符使得每个子串都是回文串的最小分割成次数.
则DP[i][j] = min(DP[i][j], min(DP[k][k]+ 1)) {0 =< k <= i} 其中s[k+1]->s[i]子串是回文的情况下;
否则DP[i][j]不可取,即DP[i][j] = -1;
取DP[i][i]为DP[i][0]-->DP[i][i-1]的最小值
*/
if(s.empty()){
return -1;
}
const int MAX = 2 * s.size();
int m = s.size() + 1;
int n = m;
int** dp = new int*[m];
for (int i = 0; i < m; i++) {
dp[i] = new int[n];
for (int j = 0; j < n; j++) {
dp[i][j] = MAX;
}
}
for (int i = 0; i < m; i++) {
//dp[i][0] = isBackWord(s.substr(0, i)) ? 0 : MAX;
dp[i][0] = isBackWord(s, 0, i-1) ? 0 : MAX;
}
for (int i = 1; i < 2; i++) {
dp[0][i] = 0;
dp[1][i] = 0;
}
// s长度从1到m时
for (int i = 1; i < m; i++) {
// 判定整个子字符串是否是回文
if(dp[i][0] == 0){
dp[i][i] = 0;
continue;
}
// 分别计算前0到前i个字符子串为回文时的情况
for (int j = 1; j < i; j++) {
//if(isBackWord(s.substr(j, i - j))){
if(isBackWord(s, j, i-1)){
dp[i][j] = dp[j][j] + 1;
dp[i][i] = min(dp[i][i], dp[i][j]);
}
}
}
int nMin = dp[m-1][n-1];
for (int i = 0; i < m; i++) {
delete[] dp[i];
}
delete[] dp;
return nMin;
}
bool isBackWord(const std::string& s){
int i = 0;
int j = s.size() - 1;
while(i < j){
if(s[i++] != s[j--]){
return false;
}
}
return true;
}
bool isBackWord(std::string& s, int begin, int end){
while(begin < end){
if(s[begin++] != s[end--]){
return false;
}
}
return true;
}
};