线性DP 之划分成回文字符串 题解

一:

问题描述:

当一个字符串正序和反序是完全相同时,我们称之为“回文串”。例如“racecar”就是一个回文串,而“fastcar”就不是。现在给一个字符串s,把它分割成若干个互不相交的回文子串,求分割的回文子串的最少个数。

输入格式:

第一行为正整数t(≤10),表示数据组数;接下来t行,每行一个完全由小写字母组成的字符串,长度不超过1000。

输出格式:

对于每组数据,输出最少回文子串数。

二:  两个问题,一是如何判断一个字符串回文,二是如何最少的划分。

问题一: 如何判断一个字符串回文 

       思路:    二维DP+记忆化搜索 +填表法     


 

      分析: 首先考虑是否存在重复子问题:   

                 存在,分析HW[i][j] 时,如果两端相等,那么答案就转移到同类型的小问题上了 即 HW [ i+1] [j-1]是否回文。

                所以 状态转移方程为: HW[i][j] =   HW[i+1][j-1] (if  S[i]==S[j])

                                                                   =  false            (else)


 

     代码:  设 bool    HW[i][j]表示 从i 到 j 是否回文。 状态转移方程为: HW[i][i] = 

     首先考虑 字符串长度为1 or 2 的情况

   

for (int i = 1; i <= n; i++)
        {
            hw[i][i] = true;
            hw[i - 1][i] = (s[i - 1] == s[i]);
        }

 

   然后考虑  字符串长度>=3的情况   

 

for (int j = 2; j <= n; j++)
        {
            for (int i = 1; i < j-1; i++)
            {
                if (s[i] == s[j])
                    hw[i][j] = hw[i + 1][j - 1];
                else hw[i][j] = false;
            }
        }

问题二:如何划分

思路:  线性DP+填表法 


 

分析: dp[i] 表示 前i个字符中最少的回文串数量,寻找重复子问题: 把前i 个字符里含有最少的回文串数  转化为 前J 个字符里含有的最少的回文串数    

 

 

 

          所以状态转移方程为:  dp[i] = min( dp[i] ,dp[j-1] +1 )        // if  HW[j][i]

                                               dp [i] = dp[i-1]+1                           //  (初始化)


 

代码:  答案就是dp[n];

for (int i = 1; i <= n; i++)
        {
            dp[i] = dp[i - 1] + 1;
            for (int j = 1; j < i; j++)
            {
                if (hw[j][i])
                    dp[i] = min(dp[i], dp[j - 1] + 1);
            }
        }
        cout << dp[n] << endl;

 

 全部代码:

#include <iostream>
using namespace std;
#include <algorithm>
int num, n;
string s;
const int maxn = 1000;
int dp[maxn];
bool hw[maxn][maxn];
int main()
{
    cin >> num;
    while (num--)
    {
        cin >> s;
        n = s.size();
        s = ' ' + s;
        for (int i = 1; i <= n; i++)
        {
            hw[i][i] = true;
            hw[i - 1][i] = (s[i - 1] == s[i]);
        }
        for (int j = 2; j <= n; j++)
        {
            for (int i = 1; i < j-1; i++)
            {
                if (s[i] == s[j])
                    hw[i][j] = hw[i + 1][j - 1];
                else hw[i][j] = false;
            }
        }
        for (int i = 1; i <= n; i++)
        {
            dp[i] = dp[i - 1] + 1;
            for (int j = 1; j < i; j++)
            {
                if (hw[j][i])
                    dp[i] = min(dp[i], dp[j - 1] + 1);
            }
        }
        cout << dp[n] << endl;
    }
    return 0;
}
//

 

posted @ 2022-04-29 14:48  ..joe  阅读(47)  评论(0编辑  收藏  举报