样例1.
输入:
6
aabcaa
输出:
1
样例2.
输入:
10 asdbdbdadb
输出:
3
思路分析:这个题要求这个字符串删了多少个之后字符之后变成了回文串,求删除字符数量的最小值。显然,回文串是从左读和从右读都相等的串,所以既然从左读和从右读相等的话,那要是先把这个字符串复制一份然后翻转一下呢?比如这个样例1 : aabcaa ,翻转之后是 aacbaa,仔细瞅瞅就会发现这好像是求两个字符串的最长公共子串啊!!!那么最小删除的字符数量就是字符串的长度删除最长公共子串的长度啊!!!
那么怎么求最长公共子串呢?
答:使用Y式动态规划分析法
状态表示:
集合:f[i][j]表示是a的前i个字母,和b的前j个字母的公共子序列长度
属性:最大值
状态计算:
(贴一位老哥画的图)
解释:当a[i] == b[i]的时候,算这俩前面的公共长度最大值,然后再加一
即:f[i][j] = f[i - 1][j - 1] + 1;
当a[i] != b[i]的时候,这个时候要讨论一下。情况一 a[i]不在最长公共子序列中,即f[i - 1][j]
情况二,b[j]不在最长公共子序列中,即f[i][j - 1]
总结:当a[i] != b[i] 的时候 f[i][j] = max(f[i][j - 1], f[i - 1][j])取这两种情况的最大值.
代码如下:(我两个字符数组用的s1和s2)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e3 + 10;
char s1[N], s2[N];
int f[N][N];
int main()
{
int n;
cin >> n;
cin >> s1 + 1;
int len = strlen(s1 + 1);
strcpy(s2 + 1, s1 + 1);//s2 = s1
reverse(s2 + 1, s2 + len + 1);//反转
for(int i = 1; i <= len; i ++)
{
for(int j = 1; j <= len; j ++)
{
if(s1[i] == s2[j])
{
f[i][j] = f[i - 1][j - 1] + 1;
}
else
{
f[i][j] = max(f[i - 1][j], f[i][j - 1]);
}
}
}
cout << len - f[len][len] << "\n";
return 0;
}