1034: 近似回文词
题目描述
输入一行文本,输出最长近似回文词连续子串。所谓近似回文词是指满足以下条件的字符串:
1. S以字母开头,字母结尾
2. a(S)和b(S)最多有2k个位置不同,其中a(S)是S删除所有非字母字符之后得到的串,b(S)是a(S)的逆序串。
比如当k=1时,Race cat是一个近似回文词,因为a(S)=racecat和b(S)=tacecar只有2个位置不同。
输入
输入包含不超过25组数据,每组数据包含两行。第一行是整数k(0<=k<=200),第二行为字符串S,包含不超过1000个字符(换行符不算)。S只包含字符、空格和其他可打印字符(比如逗号,句号),并且不会以空白字符开头。
输出
对于每组测试数据,输出最长近似回文子串的长度和起始位置(S的第一个字符是位置1)。如果有多个最长近似回文子串解,起始位置应尽量小。
样例输入 Copy
1
Wow, it is a Race cat!
0
abcdefg
0
Kitty: Madam, I'm adam.
样例输出 Copy
Case 1: 8 3
Case 2: 1 1
Case 3: 15 8
从回文字符串中间向两边双向搜索,需要处理最长字符串长度为偶数和奇数两种情况,,因为偶数情况下,会文字符串是从中间两个开始两两判断,而奇数情况下,最中间字符无需判断,直接从该字符两边开始两两判断。
AC Code:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>
#include <climits>
#include <set>
#include <stack>
#include <string>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
static const int MAX_N = 1e3 + 5;
string str;
char tar_s[MAX_N];
int ind[MAX_N];
int main() {
/*freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);*/
int k;
int cas = 0;
while (scanf("%d", &k) != EOF) {
getchar();
getline(cin, str);
int len = str.length();
int cnt = 0;
for (int i = 0; i < len; ++i) {
if (isalpha(str[i])) {
tar_s[cnt] = tolower(str[i]);
ind[cnt++] = i + 1;
}
}
int maxlen = 0, init_ind = cnt;
for (int i = 0; i < cnt; ++i) {//i表示回文字符串最中间的字符,偶数情况下为中间靠左的字符
int sum = 0;
int j = 0;
for (; i - j >= 0 && i + j < cnt; ++j) {//回文字符串长度为奇数
if (tar_s[i - j] != tar_s[i + j]) ++sum;
if (sum > k) break;
}
--j;
if (j < 0) continue;
if (ind[i + j] - ind[i - j] + 1 > maxlen) {
maxlen = ind[i + j] - ind[i - j] + 1;
init_ind = ind[i - j];
}
j = 0;
sum = 0;
for (; i - j >= 0 && i + j + 1 < cnt; ++j) {//长度为偶数
if (tar_s[i - j] != tar_s[i + j + 1]) ++sum;
if (sum > k) break;
}
--j;
if (j < 0) continue;
if (ind[i + j + 1] - ind[i - j] + 1 > maxlen) {
maxlen = ind[i + j + 1] - ind[i - j] + 1;
init_ind = ind[i - j];
}
}
printf("Case %d: %d %d\n", ++cas, maxlen, init_ind);
}
return 0;
}