题目:给定一个字符串str把str全部切成回文子串的最小分割数。
例如:str = “ABA”;不需要切割,str本身就是回文串。
str = “ACDCDCDAD” ,切割成 “A”“CDCDC”“DAD”,所以返回2。思路分析
本题是一个动态规划的问题,定义动态规划的数组dp,dp[i]表示子串str[i…..len-1]至少需要几次切割,才能把str[i…..len-1]全部切割成回文子串,那么dp[0]就是最终的结果。
从右往左依次计算dp[i],i的初始值为len-1,具体计算过程如下。
1.假设j在i和len-1之间,如果str[i…j]是一个回文串,那么dp[i]的值可能是dp[j+1]+1,因为如果str[i…j]是一个回文串,那么他就可以自己作为一部分,剩下str[j+1….len-1]继续做切割,而dp[]的计算由右到左,dp[j+1]就是str[j+1…len-1]的
最少回文分割数。
2.根据上述思路,让j在i到len-1上做枚举。所有情况中的最小值就是dp[i]的值。
如何判断是否是回文串呢?
1.定义一个二维数组,bool arr[][] ,如果arr[i][j]为true,说明str[i…j]是回文串,否则不是。
2.str[i…j]是回文串有以下三种情况。
(1)str[i…j]有一个字符组成
(2)str[i…j]有两个相等的字符组成
(3)str[i+1…j-1]是回文串,也就是arr[i+1][j-1]为true,且str[i] = str[j]。- 实现代码
#include<iostream>
#include<string>
#include<vector>
#define MAXSIZE 256
using namespace std;
int min(int left,int right)
{
return left < right ? left : right;
}
int GetMinCut(string str)
{
int len = str.size();
if (0 == len)
return -1;
char *cur = (char*)str.c_str();
bool arr[MAXSIZE][MAXSIZE] = {false};
int *dp = new int[len + 1];
dp[len] = -1;
for (int i = len - 1; i >= 0; i--)
{
dp[i] = INT_MAX;
for (int j = i; j < len; j++)
{
if (cur[i] == cur[j] && ((j -i < 2) || arr[i + 1][j - 1]))//判断是否为回文串
{
arr[i][j] = true;
dp[i] = min(dp[i],dp[j + 1] + 1);
}
}
}
return dp[0];
}
int main()
{
string str;
getline(cin, str);
int ret = GetMinCut(str);
cout << ret;
return 0;
}