5. 最长回文子串
给定一个字符串
s
,找到s
中最长的回文子串。你可以假设s
的最大长度为 1000。
步骤:
- 对于空字符串、长度为1或2的字符串进行特判;
- 申请二维数组
P
用于标记s[i]
到s[j]
之间的字符串是否为回文; - 初始化
P[i][i]
和P[i][i+1]
; P[i][i+k]=(P[i+1][i+k-1] && s[i] == s[i+k])
,k
从2
到len(s)-1
循环,i
从0
开始循环。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * longestPalindrome(char * s)
{
// Step 1
if (s == NULL)
return NULL;
int len = strlen(s);
if (len == 1)
return s;
else if (len == 2)
{
if (s[0] == s[1])
return s;
else
return NULL;
}
// Step 2 and 3
int left, right;
int **P = (int**)malloc(sizeof(int*) * len);
for (int i = 0; i < len; i++)
{
P[i] = (int*)malloc(sizeof(int) * len);
P[i][i] = 1;
}
for (int i = 0; i < len - 1; i++)
{
if (s[i] == s[i + 1])
{
P[i][i + 1] = 1;
P[i + 1][i] = 1;
}
else
{
P[i][i + 1] = 0;
P[i + 1][i] = 0;
}
}
// Step 4
for (int k = 2; k < len; k++)
{
for (int i = 0; i + k < len; i++)
{
int j = i + k;
P[i][j] = (P[i + 1][j - 1] && s[i] == s[j]);
if (P[i][j])
{
left = i;
right = j;
}
}
}
// Output result;
char* result = (char*)malloc(sizeof(char) * (right - left + 2));
for (int i = left; i <= right; i++)
result[i - left] = s[i];
result[right - left + 1] = '\0';
for (int i = 0; i < len; i++)
free(P[i]);
return result;
}
int main()
{
char str[1000];
scanf("%s", str);
printf("%s", longestPalindrome(str));
return 0;
}
拓展:一个相似的问题
给定一个字符串 S ,最少需要几次增删改操作可以把 S 变成一个回文字符串?一次操作可以在任意位置插入一个字符,或者删除任意一个字符,或者把任意一个字符修改成任意其他字符。
请编写一个程序,计算最少的操作次数并输出。 输入格式: 字符串 S,S的长度不超过100, 只包含’A’-‘Z’。 输出格式:最少的操作次数。
思路:用相同的方法遍历字符串,遍历时记录累加最少的修改次数。即:
P[i][i] = 0
,其他初始化为0x3f3f3f3f
;s[i] == s[j] && P[i][i + k] = min(P[i][j + k], P[i + 1][i + k - 1])
s[i] !=s[j] && P[i][j]=min(P[i][j],P[i+1][j]+1,P[i][j-1]+1,P[i+1][j-1]+1)