本文共 1866 字,大约阅读时间需要 6 分钟。
动态规划是一种在字符串处理中常用的算法,特别适用于寻找最长子串满足特定条件的问题。本文将介绍如何利用动态规划来找到字符串中的最长回文子串。
为了判断一个子串是否是回文,我们需要定义一个状态:P(i, j)
表示从索引 i
到 j
的子串是否是回文。根据回文串的性质,如果子串长度为2或以上,并且首尾字符相同,那么去掉首尾字符得到的中间子串也必须是回文。因此,状态转移方程可以定义为:
P(i, j) = P(i+1, j-1) 且 s[i] == s[j]
对于长度为1的子串,直接视为回文;长度为2的情况,只需检查首尾字符是否相等。
初始化:创建一个二维数组 dp[n][n]
,其中 n
是字符串的长度。对角线上的元素 dp[i][i]
初始化为 true
,因为长度为1的子串是回文。
填充状态转移表:从长度 2
到 n
,逐步填充状态表。对于每个子串长度 L
,遍历每个可能的起始索引 i
,计算结束索引 j = i + L - 1
。如果 j
超出字符串长度,跳过当前情况;否则,检查字符 s[i]
和 s[j]
是否相等,以及对应的中间子串 dp[i+1][j-1]
是否为回文。
记录最大值:在状态转移过程中,记录最长回文子串的长度和起始位置。当 dp[i][j]
为 true
且当前子串长度大于已记录的最大值时,更新最大值并记录起始位置。
以下是用 Java 语言实现的动态规划解决方案:
public class Solution { public String longestPalindrome(String s) { int len = s.length(); if (len == 0) return ""; boolean[][] dp = new boolean[len][len]; int maxLen = 1; int begin = 0; // 初始化对角线 for (int i = 0; i < len; i++) { dp[i][i] = true; } // 组建dp表 for (int L = 2; L <= len; L++) { // L 是长度 for (int i = 0; i <= len - L; i++) { // i 是起始位置 int j = i + L - 1; // 结束位置 if (s.charAt(i) != s.charAt(j)) { dp[i][j] = false; } else if (L < 3) { dp[i][j] = true; } else { dp[i][j] = dp[i + 1][j - 1]; } if (dp[i][j] && L > maxLen) { maxLen = L; begin = i; } } } return s.substring(begin, begin + maxLen); }}
初始化:创建一个 len x len
的布尔数组 dp
。对角线元素 dp[i][i]
初始化为 true
,表示单个字符都是回文。
填充状态转移表:
L
从 2
到 len
。i
,计算结束索引 j = i + L - 1
。s[i]
和末字符 s[j]
是否相同,并结合中间子串是否是回文来确定 P(i, j)
。记录最长回文子串:每次检查当前子串是否为回文且长度是否大于已记录的最大长度,如果满足则更新最大值和起始位置。
这种方法充分利用动态规划的性质,从小的子串逐步构建最长回文子串,时间复杂度为 O(n²),适用于题目给定的字符串长度限制。
转载地址:http://iachz.baihongyu.com/