LeetCode 5 最长回文子串
问题描述:
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
动态规划
执行用时:209 ms, 在所有 Java 提交中击败了12.42%的用户
内存消耗:50.1 MB, 在所有 Java 提交中击败了5.01%的用户
class Solution{
//动态规划
//dp[i][j]表示str[i, j]范围内最长回文子串长度, j>=i
//dp[i][j]与dp[i+1][j]、dp[i][j-1]、dp[i+1][j-1]有关
//1. 若str[i]==str[j] and dp[i+1][j-1]==j-(i+1)
// dp[i][j] = dp[i+1][j-1]+2
//2. 其它情况
// dp[i][j] = max{dp[i+1][j], dp[i][j-1], dp[i+1][j-1]}
//初始: dp[i][i] = 1
public String longestPalindrome(String s) {
if(s==null || s.length()<=1) {
return s;
}
int[][] dp = new int[s.length()][s.length()];
//状态初始化
for(int i=0; i<s.length(); i++) {
dp[i][i] = 1;
}
//状态递推O(N2)
int left = 0, right = 0;
//遍历方式存在问题(保证后有效性)
for(int j=0; j<s.length(); j++) {
for(int i=0; i<=j; i++) {
if(i==j) {
continue;
}
//考虑奇对称、偶对称两种情况下的初始情况(两个值、三个值)
if(s.charAt(i)==s.charAt(j)
&& (i+1==j || dp[i+1][j-1]==(j-i-1))) {
dp[i][j] = j+1-i;
}
else {
dp[i][j] = Math.max(
i+1==j? 0: dp[i+1][j-1],
Math.max(dp[i+1][j], dp[i][j-1])
);
}
//记录字符串起始坐标
if(right+1-left < dp[i][j] && dp[i][j]==j+1-i) {
left = i;
right = j;
}
}
}
return s.substring(left, right+1);
}
}
暴力优化: 中心扩散
执行用时:58 ms, 在所有 Java 提交中击败了59.81%的用户
内存消耗:37.6 MB, 在所有 Java 提交中击败了67.40%的用户
//问题描述:在给定字符串中找到最长的回文“子串”,回文子串的定义为:字符串对称分布,即从左到右、从右到左遍历输出一致
/**动态规划:
* 状态转移:Sub[i,j]表示arr[i]..arr[j]组成的子串
* 若Sub[i,j]是回文串,则需要满足:Sub[i+1,j-1]是回文串,且arr[i] == arr[j]
* 递推:找到一个最小的回文串,例如"aa"、"aba",由该回文串向外扩展
* */
//O(N2/2)
class Solution{
public String longestPalindrome(String s) {
if(s.length()<=1) return s;
if(s.length()==2) return (s.charAt(0)==s.charAt(1))?s:s.charAt(0)+"";
int maxLen = 1, minLeft = 0, maxRight = 0;
//1、找到一个最小的回文串(由第二个向倒数第二个寻找)
//2、由最小回文串向两边扩展,找到一个最长的回文串
//时间复杂度:O(N2)
for(int i=1;i<s.length()-1;i++){
//偶数
if(s.charAt(i)==s.charAt(i-1)){
int currLen = searchPalindrome(s, i-1, i);
if(maxLen < currLen){
maxLen = currLen;
minLeft = i - currLen/2;
maxRight = i-1 + currLen/2;
}
}
if(s.charAt(i) == s.charAt(i+1)){
int currLen = searchPalindrome(s, i, i+1);
if(maxLen < currLen){
maxLen = currLen;
minLeft = i+1 - currLen/2;
maxRight = i + currLen/2;
}
}
//奇数
if(s.charAt(i-1)==s.charAt(i+1)){
int currLen = searchPalindrome(s, i-1, i+1);
if(maxLen < currLen){
maxLen = currLen;
minLeft = i - currLen/2;
maxRight = i + currLen/2;
}
}
}
System.out.println("maxLen="+maxLen);
return s.substring(minLeft, maxRight+1);
}
public int searchPalindrome(String s, int i, int j){
int maxLen = j-i+1;
i--;j++;
while(i>=0 && j<s.length()){
if(s.charAt(i) != s.charAt(j)) break;
maxLen += 2;
i--;j++;
}
return maxLen;
}
}