[PAT_A 1040]Longest Symmetric String

在这里插入图片描述

题目大意:
给出一个字符串,求最长回文子串。

思路:
用dp[i][j]表示s[i]至s[j]所表示的子串是否是回文子串,是则为1,不是则为0。
若s[i]==s[j],那么只要s[i+1]至s[j-1]是回文串,则s[i]到s[j]是回文串。如果s[i+1]到s[j-1]不是回文串,那么s[i]至[j]也不是回文串。
若s[i]!=s[j],那么s[i]到s[j]一定不是回文串。

状态转移方程:
1)s[i]==s[j] dp[i][j]=dp[i+1][j-1].
2)s[i]!=s[j] dp[i][j]=0.

边界dp[i][i]=1,dp[i][i+1]=(s[i]==s[i+1])?1:0.

如果按照ij的从小到大的顺序来枚举两个子串的两个端点,然后更新dp[i][j],会无法保证dp[i+1][j-1]已经被计算过,从而无法得到正确的dp[i][j].
由于边界表示为长度为1和2的子串,且每次转移时都对子串的长度减1,可以考虑按照子串的长度 与子串的初始位置进行遍历,如第一遍遍历长度为3的子串,第二遍再计算出长度为4的子串…,子串长度最多可以取到S.length()。

AC代码:

//PAT_A 1040
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1010;
char s[maxn];
int dp[maxn][maxn];
int main() {
	(void)scanf("%[^\n]", s);
	int len = strlen(s), ans = 1;
	memset(dp, 0, sizeof(dp));
	for (int i = 0; i < len; i++) {
		dp[i][i] = 1;//长度为1的子串
		if (i < len - 1) {
			if (s[i] == s[i + 1]) {//长度为2的子串
				dp[i][i + 1] = 1;
				ans = 2;//最长回文子串
			}
		}
	}
	for (int l = 3; l <= len; l++) {
		for (int i = 0; i + l - 1 < len; i++) {//枚举左串的起始顶点
			int j = i + l - 1;//右端点
			if (s[i] == s[j] && dp[i + 1][j - 1] == 1) {
				dp[i][j] = 1;
				ans = l;
			}
		}
	}
	printf("%d\n", ans);
	return 0;
}
发布了142 篇原创文章 · 获赞 1 · 访问量 4558

猜你喜欢

转载自blog.csdn.net/weixin_44699689/article/details/104702956