动态规划之回文最小分割数

  • 题目:给定一个字符串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;
}
点赞