LeetCode · 动态规划 · 专题

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])k2len(s)-1循环,i0开始循环。
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 
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)

你可能感兴趣的:(LeetCode · 动态规划 · 专题)