开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情
LeetCode15:最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入: s = "babad"
输出: "bab"
解释: "aba" 同样是符合题意的答案。
示例 2:
输入: s = "cbbd"
输出: "bb"
示例 3:
输入:s = "a"
输出:"a"
示例 4:
输入:s = "ac"
输出:"a"
解释: "c" 同样是符合题意的答案。
提示:
1 <= s.length <= 1000s仅由数字和英文字母组成
思路分析
题目求最长回文子串,算法题练习多了,对于本题其实很自然就想到动态规划方法来解。
直接按照动态规划步骤来:
- 定义一个dp数组,确定其下标所表示的含义
dp[i][j]:表示区间[i,j](左闭右闭)子串是否为回文子串,若是 dp[i][j]为true,否则为false
-
推导出递推公式
要确定递推公式,需考虑两种情况:(1)s[i]与s[j]相等,(2)s[i]与s[j]不相等- s[i]与s[j]不相等时,dp[i][j]必定为false
- s[i]与s[j]相等时,会有三种不同情况:
- 下标i 与 j相同,表示同一个字符(例如a),肯定是回文子串
- 下标i 与 j相差为1,如:aa,也是回文子串
- i 与 j相差大于1时,s[i]与s[j]已经相同,只需要确定dp[i + 1][j - 1]是否为true即可
s[i]和s[j]相等,并且子串i+1..j-1是回文串的话,子串i..j肯定也是回文串。即:如果s[i] == s[j]且dp[i+1][j-1] = true时,dp[i][j] = true
-
dp数组初始化值: dp[i][j]初始化应为false
-
遍历顺序
- 首先从递推公式中可以看出,根据dp[i + 1][j - 1]是否为true,再对dp[i][j]进行赋值true
- 要从下到上,从左到右遍历,确保dp[i + 1][j - 1]都经过计算
-
根据递推公式确认dp数组所有元素
- dp[i][j]的定义,所以j一定是大于等于i的,那么在填充dp[i][j]的时候一定是只填充右上半部分
算法代码
public String longestPalindrome(String s) {
if (s.isEmpty()) { // 判空校验
return s;
}
int n = s.length();
boolean[][] dp = new boolean[n][n]; // 创建二维数组dp
int left = 0;
int right = 0;
for (int i = n - 2; i >= 0; i--) {
dp[i][i] = true;
for (int j = i + 1; j < n; j++) {
//小于3是因为aba一定是回文
dp[i][j] = s.charAt(i) == s.charAt(j) &&( j-i<3||dp[i+1][j-1]);
if(dp[i][j]&&right-left<j-i){ // 更新区间边界
left=i;
right=j;
}
}
}
return s.substring(left,right+1);
}
算法复杂度
- 时间复杂度
- 空间复杂度
在掘金(JUEJIN)一起进步,一起成长!