LeetCode5 :最长回文子串
题目:
给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
思路:
- dp[i][j] 表示从字符数组的下标i 开始到下标j 的子序列 s[i,i+1,..j] 是否是回文串
- 从数组下标 left到right的子序列,跟从left + 1 到 right - 1的子序列,要么都是回文串,要么都不是回文串。
- 可以枚举子序列的长度subLength ,以及左下标left ,由 subLength 和 left 可以确定右边界
易错点:
- //注意,长度低于2的直接就是回文子串了
- //注意,子串长度subLength是从2开始的,并且要小于等于 length
- //注意,由 子串长度subLength 和 左下标 left 可以确定右边界,即 right - left + 1 = subLength
- //注意:substring不要写错了,语法是左开右闭,注意边界问题
- //注意:超出索引就跳过,要小心数组越界的问题
代码:
/**
* 对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。
*
* P(i,j) 表示字符串 s 的第 i 到 j 个字母组成的串。(s[i:j] 类似)
*
* (1)状态转移方程:
*
* P(i,j)=P(i+1,j−1)∧(Si==Sj)
* 也就是:只有 s[i+1:j−1] 是回文串,并且 s 的第 i 和 j 个字母相同时,s[i:j] 才会是回文串。
*
* (2)初始值:
* 对于长度为 1 的子串,它显然是个回文串;
* 也就是 P(i,i)=true;
*
* 对于长度为 2 的子串,只要它的两个字母相同,它就是一个回文串。因此我们就可以写出动态规划的边界条件:
* 也就是P(i,i+1)= (Si==Si+1)
*
* 详情见: https://leetcode.cn/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/
*
* @param s
* @return
*/
public String longestPalindrome(String s) {
int length = s.length();
//注意,长度低于2的直接就是回文子串了
if (length < 2) {
return s;
}
int maxLength = 1;
int begin = 0;
// dp[i][j] 表示从字符数组的下标i开始到下标j的子序列 s[i,i+1,..j] 是否是回文串
boolean[][] dp = new boolean[length][length];
// 初始化:所有长度为 1 的子串都是回文串
for (int i = 0; i < length; i++) {
dp[i][i] = true;
}
char[] charArray = s.toCharArray();
// 递推开始
// 先枚举子序列的长度
//注意,子串长度subLength是从2开始的,并且要小于等于 length
for (int subLength = 2; subLength <= length; subLength++) {
// 枚举左边界,左边界的上限设置可以宽松一些
for (int left = 0; left < length; left++) {
//注意,由 子串长度subLength 和 左下标 left 可以确定右边界,即 right - left + 1 = subLength
int right = subLength + left - 1;
// 如果右边界越界,就可以退出当前循环
//注意:超出索引就跳过,要小心数组越界的问题
if (right >= length) {
break;
}
if (charArray[left] != charArray[right]) {
//子序列的左边界和右边界的值,如果不相同,就不可能是回文串
dp[left][right] = false;
} else {
//左边界和右边界相同时,子序列的长度为1或为2,都是回文串。
if (right - left < 3) {
dp[left][right] = true;
} else {
//状态转移方程,左边界和右边界相同时,
// 从left到right的子序列,跟从left + 1 到 right - 1的子序列,要么都是回文串,要么都不是回文串。
dp[left][right] = dp[left + 1][right - 1];
}
}
// 只要 dp[left][subLength] == true 成立,就表示子串 s[left..subLength] 是回文,此时记录回文长度和起始位置
if (dp[left][right] && right - left + 1 > maxLength) {
//找出最大子序列的长度
maxLength = right - left + 1;
begin = left;
}
}
}
//注意:substring不要写错了,语法是左开右闭,注意边界问题
return s.substring(begin, begin + maxLength);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2022-01-26 Dubbo使用Rest开发服务