题目描述Leetcode-2019-第 10 场双周赛第四题
给出一个字符串 s 和一个整数 k,请你帮忙判断这个字符串是不是一个「K 回文」。
所谓「K 回文」:如果可以通过从字符串中删去最多 k 个字符将其转换为回文,那么这个字符串就是一个「K 回文」。
示例
输入:s = “abcdeca”, k = 2
输出:true
解释:删除字符 “b” 和 “e”。
提示:
- 1 <= s.length <= 1000
- s 中只含有小写英文字母
- 1 <= k <= s.length
思路分析
这个题在比赛中属于压轴题,困难级别,但是掌握了方法还是挺简单的。我的思路如下:
这个题和我之前做的寻找最短编辑距离的一道题有点类似(点击了解详情),这个题的思路类似,首先,我们要比较头尾,这是我们大家都知道的思路,所以我采取二维数组进行存储行表示正序的字符串,列表示逆序的字符串,如图
其中数字部分就是二维数组的分布。
基础弄好后,我们如何利用二维数组表示一个关键点。先拿出我的代码实现
for (i = 1; i <= len; i++)
{
for (j = 1; j <= len; j++)
{
if (str[i - 1] == basestr[j - 1])
Map[i][j] = Map[i - 1][j - 1];
else
Map[i][j] = Map[i - 1][j] > Map[i][j - 1] ? ( Map[i][j - 1] + 1) : ( Map[i - 1][j] + 1 );
}
}
首先,逆序的每一行的一个字母于正序的所有字母进行比较,如图黄色部分和红色部分进行比较,如果两个字母相等,比如黄色的a和红色的a,那么Map[ 1 ] [ 1 ]就应该等于左上角Map[ 0 ] [ 0 ]的值,为什么这么做呢?原因很简单,我们会发现位于主对角线上的值都是最优解,因为主对角线是两边比较的字符串长度相等时的情况。
如果不相等,那么取Map左边或者上边较小值+1赋给Map [ i ] [ j ]即可
因为每一个小格子都是目前最优解,我们需要选取最小的即可。
代码解析
#include<iostream>
#include<cstring>
using namespace std;
constexpr auto Maxsize = 1001;
int Map[Maxsize][Maxsize];//比较数组
int F(char str[ ],char basestr[ ], int k)
{
int i, j,len = strlen(str);
for (i = 1; i <= len; i++)//行
{
for (j = 1; j <= len; j++)//列
{
if (str[i - 1] == basestr[j - 1])//相等的时候取左上角Map值
Map[i][j] = Map[i - 1][j - 1];
else//不相等的时候取Map左边或者上边较小值+1
Map[i][j] = Map[i - 1][j] > Map[i][j - 1] ? ( Map[i][j - 1] + 1) : ( Map[i - 1][j] + 1 );
}
}
if (Map[len][len] % 2 == 0)//为偶数时,最终解为最后的一半
return Map[len][len] / 2;
else//为奇数时,加一
return Map[len][len] / 2 + 1;
}
int main()
{
char str[Maxsize],basestr[Maxsize];
int k;
cout << "请输入字符串:" ;
cin >> str;
int len = strlen(str);
cout << "请输入判断条件 k 回文:";
cin >> k;
memset( Map, 0, sizeof(Map) );
memset(basestr, 0, sizeof(basestr));
for (int i = len; i >= 0; i--)//第一行和第一列赋初值自身的长度,很显然就是最大值
{
Map[0][i] = i;
Map[i][0] = i;
}
for (int temp = 0; temp < len; temp++)//逆序存储字符便于判断
basestr[temp] = str[len - temp - 1];
if ( F(str, basestr, k) == k)
cout << "true"<<endl;
else
cout << "false" << endl;
return 0;
}
运行结果