题目描述
回文词是一种对称的字符串。任意给定一个字符串,通过插入若干字符,都可以变成回文词。此题的任务是,求出将给定字符串变成回文词所需要插入的最少字符数。
比如 “Ab3bd”插入2个字符后可以变成回文词“dAb3bAd”或“Adb3bdA”,但是插入少于2个的字符无法变成回文词。
注:此问题区分大小写
输入格式
一个字符串(0<strlen<=1000)
输出格式
有且只有一个整数,即最少插入字符数
输入输出样例
输入 #1
Ab3bd
输出 #1
2
解题思路:该题说是考察如何将一个字符串添加成一个回文串的,不如说是一道求最长公共自序列的变式题,为啥这么说呢?肯定是有原因在里面的
-
首先,我们要摸清回文串的特性,回文就是正着读反着读一样,一种非常对称不会逼死强迫症的字符串;这就是我的突破口;
-
我们先分析下样例:ab3bd,
-
它的倒序是:db3ba
这样我们就可以把问题转化成了求最长公共自序列的问题,为啥可以这么转化呢?
它可以这么理解,正序与倒序“公共”的部分就是我们回文的部分,如果把正序与倒序公共的部分减去你就会惊奇的发现剩余的字符就是你所要添加的字符,也就是所求的正解
#include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> using namespace std; int n; int dp1[5001],dp2[5001]; //此处用两个滚动数组记录,一个记录之前的状态,一个记录此时的状态 char str1[5001],str2[5001]; int main() { //freopen("palindrome.in", "r", stdin); //freopen("palindrome.out", "w", stdout); scanf("%s", str1+1); n = strlen(str1+1); for(int i = 1; i <= n; i++) str2[i] = str1[n-i+1]; //做一个逆序的字符串数组 for(int i = 1; i<=n; i++) { for(int j = 1; j <= n; j++) if(str1[i] == str2[j]) dp1[j] = dp2[j-1]+1; //“发现”匹配就记录 else dp1[j] = max(dp1[j-1],dp2[j]); //不匹配就匹配后面的状态 memcpy(dp2, dp1, sizeof(dp1)); //记录之前的状态“滚动”匹配 } printf("%d\n", n-dp1[n]); //字符串长度减去匹配出的最长公共自序列的值 return 0; //即需要添加的字符数 }
这种解法用一维数组代替二维数组中的状态量,合理控制内存也可以顺利AC。
2021.8.6计算机201 叶俊