LeetBook刷题笔记007:最长回文子串(Java实现)
题目
给你一个字符串 s
,找到 s
中最长的回文子串
最优解:动态规划
状态转移方程
P(i,j)=P(i+1,j−1)∧(Si==Sj)
- 以字符串长度作为变化由短向长转换
public static String longestPalindrome(String s) {
//提前获取字符串长度提升效率
int n=s.length();
//排除明显的特殊情况
if(n<2)
return s;
//创建dp数组记录i到t的子串是否为回文字符串
boolean[][] dp=new boolean[n][n];
//单个字符本身为回文字符串进行初始化
for(int i=0;i<n;i++)
dp[i][i]=true;
//初始化为1防止最大长度为1导致无法返回
int length=1;
//存储回文字符串开始索引
int d=0;
//因为通过长度变化进行转换而建立循环
for(int len=2;len<=n;len++){
//设置循环n-len+1次防止右区间t越界
for(int i=0;i<n-len+1;i++){
int t=len+i-1;
//每次判断区间两端字符即可
if(s.charAt(i)==s.charAt(t)){
//特殊处理2个字符的情况
//由于3个字符同样符合可统一处理
//两端字符相等则当前子串是否是回文串由内部子串决定
if(t-i<3)
dp[i][t]=true;
else
dp[i][t]=dp[i+1][t-1];
}else
dp[i][t]=false;
//若当前区间字符串为回文串则记录其长度及开始索引
//同时length<len防止重复记录相同长度的子串
if(dp[i][t]&&length<len){
d=i;
length=len;
}
}
}
//最后将字符串截取出得到的最大回文数直接返回
return s.substring(d,d+length);
}
//时间复杂度:O(n^2)
最优解:中心扩散
class Solution {
public String longestPalindrome(String s) {
//存储左区间索引
int start=0;
//存储右区间索引
int end=0;
//提前获取字符串长度提升效率
int n=s.length();
for(int i=0;i<n;i++){
//注意奇偶字符串要分别进行扩散
//使用函数进行重复的扩散操作
int l1=length(s,i,i);
int l2=length(s,i,i+1);
//比较每次获取的奇偶字符串长度
int len=Math.max(l1,l2);
//更新最大长度
if(len>end-start){
//根据获取的长度和中心索引获取左右区间的索引
//注意要对长度进行调整
start=i-(len-1)/2;
end=i+len/2;
}
}
//截断源字符串返回最大子回文串并直接返回
return s.substring(start,end+1);
}
public static int length(String s,int a,int b){
while(a>=0&&b<=s.length()&&s.charAt(a)==s.charAt(b){
a--;
b++;
}
return b-a-1;
}
}