【LeetCode 5-中等】最长回文子串(高清截图)

5. 【中等】最长回文子串

https://leetcode-cn.com/problems/longest-palindromic-substring/
给你一个字符串s,找到s中最长的回文子串。

示例 1:
	输入:s = "babad"
	输出:"bab"
	解释:"aba" 同样是符合题意的答案。
示例 2:
	输入:s = "cbbd"
	输出:"bb"
示例 3:
	输入:s = "a"
	输出:"a"
示例 4:
	输入:s = "ac"
	输出:"a"

提示:
1 <= s.length <= 1000
s仅由数字和英文字母(大写和/或小写)组成

【解】

【方法1】动态规划(DP)。


P(i, j)={█(“true” &, s[i, j]“是回文串” @“false” &, s[i, j]“不是回文串,或不合法(” i>j")" )┤
若字符串s的某个子串s[i, j]是回文串,且最邻近它两端的字符均相等,即s[i-1]==s[j+1],则字符串s[i-1, j+1]也是回文串。因此,状态转移方程
{█(P(i, j)&=P(i+1, j-1)∧s[i]==s[j]@P(i, i)&=“true” @P(i, i+1)&=s[i]==s[i+1] )┤
易得边界条件:长为1的字符串本身就是其最长回文子串;长为2的字符串,要么它本身为它的最长回文子串,要么它没有任何回文子串。
实现的时候要注意,一个字符串s的长度大于2的子串s[i, j]是否为s的最长回文子串,需要凭借之前已经判定过的长度更短的字串的判定结果来做出判定。
代码:

#include <vector>

class Solution {
    
    
public:
	string longestPalindrome(const string& s) {
    
    
		if (s.size() < 2) return s;							// 长度为 1 的字符串本身就是其最长回文子串
		const size_t n = s.size();							// 字符串 s 的长度记为 n
		size_t lmax = 1;									// 最大长度
		size_t lp_begin = 0;								// 一个最长回文子串的起始位置
		vector<vector<bool>> p(n, vector<bool>(n));			// p[i][j] 表示:字符串 s[i, j] 是否为回文串
		for (size_t i = 0; i < n; ++i) p[i][i] = true;		// 长为 1 的全部子串都是回文串
		for (size_t l = 2; l <= n; ++l) {
    
    					// 枚举长为 l = 2, 3, ..., n 的子串
			for (size_t i = 0, j; i < n; ++i) {
    
    				// 枚举长为 l 的子串的全部可能出现的位置
				j = l + i - 1;
				if (j >= n) break;							// 下标越界,字符串非法
				if (s[i] != s[j]) p[i][j] = false;
				else {
    
    
					if (j - i < 3) p[i][j] = true;			// 正在考察的字符串 s[i, j] 长为 1 或 2,且 s[i] == s[j],它应当是回文串
					else p[i][j] = p[i + 1][j - 1];			// 根据之前枚举过的长度更短的字符串,判定本字符串 s[i, j] 是否为回文串
				}
				if (p[i][j] && j - i + 1 > lmax) {
    
    			// 更新最长回文子串的统计数据
					lmax = j - i + 1;
					lp_begin = i;
				}
			}
		}
		return s.substr(lp_begin, lmax);					// 给出一个解
	}
};
用时:584 ms,短于26.94%的用户;内存占用:29.2 MB,少于55.93%的用户。

【方法2】从回文中心向两端扩展

枚举全部长度为1或2的子串,不断考察分别与子串两端相邻的2个字符。若添加这2个字符后,新子串仍为回文串,则继续如此添加下去,直到不能再添加为止。
代码:

#include <vector>

class Solution {
    
    
	pair<ptrdiff_t, ptrdiff_t> ExpandFromPalindromicCenter(const string& S, ptrdiff_t L, ptrdiff_t R) {
    
    
		while (L >= 0 and R < S.size() and S[L] == S[R]) {
    
     --L; ++R; }
		return {
    
     L + 1, R - 1 };
	}
public:
	string longestPalindrome(const string& s) {
    
    
		ptrdiff_t L = 0, R = 0;
		for (ptrdiff_t i = 0; i < s.size(); ++i) {
    
    
			auto [L1, R1] = ExpandFromPalindromicCenter(s, i, i);			// 回文中心为一个字符的情况
			auto [L2, R2] = ExpandFromPalindromicCenter(s, i, i + 1);		// 回文中心为两个字符的情况
			if (R1 - L1 > R - L) {
    
     L = L1; R = R1; }
			if (R2 - L2 > R - L) {
    
     L = L2; R = R2; }
		}
		return s.substr(L, R - L + 1);
	}
};
用时:16 ms,优于92.08%的用户;内存占用:6.9 MB,优于95.08%的用户。

【方法3】Manacher算法

(待填坑)

在这里插入图片描述

おすすめ

転載: blog.csdn.net/COFACTOR/article/details/121314984
おすすめ