给定一个字符串 s
,找到 s
中最长的回文子串。你可以假设 s
的最大长度为 1000。
示例 1:
输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd" 输出: "bb"
查找最长回文串,我们需要一定要遍历所有的子串,不管是动态规划,还是暴力求解。动态规划比暴力求解先进的地方就是我们可以重复利用以前已经计算过的值,换而言之就是,动态规划一定具有最优子结构(问题的最优解一定是由子问题最优解构成的)。要想动态规划比暴力解法先进,还要满足重叠子问题这样的条件,正因为有重叠子问题,我们才可以保存这些子问题的值,供后续计算更大子问题的值来使用而不必重新计算,从而节省了时间。不去讲这些头疼的概念。
回归本问题:
我们知道,判断一个字符串是不是回文串,我们需要扫描全部字符串,判断前后是否相同。幸运的是,判断是否为回文串,正好是递归的。比如有字符串s={s1,s2,···,sn},如果s为字符串,则串{s2,s3,···,s(n-1)}一定是回文串。我们利用这个性质,来思考如何用动态规划的方式解决他。对于串s,我们要想找出s的最长回文串,必须要遍历到s所有的子串(不一定要每一个都判断是否是回文串,因为可以利用以前的结果的话,就不用重新计算一次了)。
第一点:我们用m[begin][end]:表示从begin位置到end位置的子串是否是回文串。所以,对于任意一个从i位置开始子串j位置结束的子串来说,我们只需要判断s[i]==s[j]吗?如果相等,而m[i-1][j-1]又是回文标志的话,我们就可以将m[i][j]标志为回文串。
第二点:当判断s[i··j]时,我们希望s[i+1··j-1]已经是回文的,这样就可以利用以前的结果了。how to do? 办法很简单,反正是要遍历所有的子串,我们从小串开始判别就是了,我们用step表示串的长度,for step=1 to n,都判断下来就是了。问题得解。上代码,19行的i就是此处的step。
1 class Solution { 2 public static String longestPalindrome(String s) { 3 int len = s.length(); 4 int[][] m = new int[1000][1000];//初始化 5 int i,j,maxLength = 1, label= 0; 6 if(len == 1) return s; 7 else if(len == 0) return ""; 8 for(i=0;i<len-1;++i){ 9 m[i][i] =1; 10 if(s.charAt(i) == s.charAt(i+1)) { 11 m[i][i + 1] = 1; 12 if(maxLength < 2) { 13 maxLength = 2; 14 label = i+1; 15 } 16 } 17 } 18 m[len-1][len-1] = 1; 19 for(i=2;i<len;++i){ 20 for(j=0;j+i<len;++j){ 21 if(s.charAt(j) == s.charAt(j+i) && m[j+1][j+i-1] != 0){ 22 m[j][j+i] = 1; 23 if(i+1 > maxLength){ 24 maxLength = i+1; 25 label = j+i; 26 } 27 } 28 } 29 } 30 return s.substring(label-maxLength+1,label+1); 31 } 32 }