5.最长回文子串

LeetCode参考:https://leetcode.cn/problems/longest-palindromic-substring/description/

算法设计思路

回文串的性质:对于一个子串而言,如果它是回文串,并且长度大于 2 2 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。例如对于字符串 “ababa”,如果我们已经知道 “bab”是回文串,那么 “ababa”一定是回文串。

原问题的解可以由子问题得到,因此可以使用动态规划解决该问题。

我们用 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示字符串 s s s i i i 开始,以 i i i 结尾的回文串长度:

  • 若不是回文串,则 d p [ i ] [ j ] = 0 dp[i][j] = 0 dp[i][j]=0;
  • 若是回文串,则 d p [ i ] [ j ] dp[i][j] dp[i][j] 记录回文串的长度。

在填充 d p dp dp 数组的过程中,从斜对角线依次往右上填充:

  • 如果 i > j i > j i>j,则根本不是合法的子串,填充为 0 0 0
  • 如果 i = = j i == j i==j,即为斜对角线上的元素,填充为 1 1 1
  • 如果子串长度为 2 2 2,判断 s [ i ] = = s [ j ] s[i]==s[j] s[i]==s[j]
    • 如果 s [ i ] = = s [ j ] s[i]==s[j] s[i]==s[j],则 d p [ i ] [ j ] = 2 dp[i][j] = 2 dp[i][j]=2;
    • 否则,保持为 0 0 0 不变。
  • 如果子串长度不小于 3 3 3,判断 s [ i ] = = s [ j ] s[i]==s[j] s[i]==s[j] s [ i + 1 , j − 1 ] s[i+1, j-1] s[i+1,j1] 是否为回文串:
    • 如果 s [ i ] = = s [ j ] s[i]==s[j] s[i]==s[j] s [ i + 1 , j − 1 ] s[i+1, j-1] s[i+1,j1] 为回文串,则 dp[i][j]=dp[i+1][j1]+2
    • 否则,保持为 0 0 0 不变。

在填充过程中设置”锚点“:rowcol,用于回到每一个斜列开始位置。

在求出 d p dp dp 数组后,遍历 d p dp dp 数组,找到最长回文子串的长度,根据 i i i j j j 构造出解,即最长回文子串。

s = s = s= b a b a d babad babad” 为例,算法的运行过程如下:

源码

class Solution {
public String longestPalindrome(String s) {
if (s == "" || s.length() == 0) {
return "";
}
int n = s.length();
// dp[i][j] 表示字符串索引从 i 到 j 的子串是不是回文串,如果是,填写回文串长度,否则,填充0
int[][] dp = new int[n][n];
// 最长回文子串
String str = null;
int i = 0; // 行
int j = 0; // 列
// 锚点,记录每一斜列的开始位置
int row = 0;
int col = 0;
// 填充dp数组
while (row < n && col < n) {
// i == j, 只有一个字符的字符串
while (i == j && i < n && j < n) {
dp[i][j] = 1;
i++;
j++;
}
// 子串长度为2
while ((j - i + 1) == 2 && i < n && j < n) {
if (s.charAt(i) == s.charAt(j)) {
dp[i][j] = 2;
}
i++;
j++;
}
// 子串长度不小于3
while ((j - i + 1) >= 3 && i < n && j < n) {
// 如果s[i..j]是回文子串,那么去掉s[i]和s[j]也是回文子串
if (s.charAt(i) == s.charAt(j) && (dp[i + 1][j - 1] != 0)) {
dp[i][j] = dp[i + 1][j - 1] + 2;
}
i++;
j++;
}
i = row;
j = col + 1;
row = i;
col = j;
}
// 遍历dp数组,找出最长回文子串的长度,构造解
int maxLen = 0;
for (int p = 0; p < n; p++) {
for (int q = 0; q < n; q++) {
if (dp[p][q] == 0 ) continue;
if (dp[p][q] > maxLen) {
maxLen = dp[p][q];
str = s.substring(p, q + 1);
}
}
}
return str;
}
}
posted @   gengduc  阅读(16)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示