5.Longest Palindromic Substring---dp
题目链接:https://leetcode.com/problems/longest-palindromic-substring/description/
题目大意:找出最长回文子字符串(连续)。
法一:暴力,三层for循环,超时。代码如下:
1 public String longestPalindrome(String s) { 2 String res = ""; 3 //逐一检查每个子字符串 4 for(int i = 0; i < s.length(); i++) { 5 for(int j = i + 1; j < s.length(); j++) { 6 String tmp = s.substring(i, j + 1); 7 if(isPalindrome(tmp) == true) { 8 if(tmp.length() > res.length()) { 9 res = tmp; 10 } 11 } 12 } 13 } 14 if(res.length() == 0) { 15 res = String.valueOf(s.charAt(0)); 16 } 17 return res; 18 } 19 //判断子字符串是否是回文 20 public static boolean isPalindrome(String s) { 21 for(int i = 0, j = s.length() - 1; i < j; i++, j--) { 22 if(s.charAt(i) != s.charAt(j)) { 23 return false; 24 } 25 } 26 return true; 27 }
法二(借鉴):dp,依次计算长度为1,2,3,。。。n的所有子字符串是否是回文,只是每次计算的时候都可以直接沿用上一次计算的结果,这样可以不用for循环判断,也就是减少了一层for循环。dp公式:dp[i, j]=ture表示初始下标为i,终点下标为j的字符串是回文字符串,dp[i, j]=true当且仅当dp[i+1, j-1]=true。代码如下(耗时71ms):
1 public String longestPalindrome(String s) { 2 int length = s.length(); 3 boolean dp[][] = new boolean[length][length]; 4 int start = 0, maxLength = 1; 5 //初始化回文长度是1-2 6 for(int i = 0; i < length; i++) { 7 dp[i][i] = true; 8 if(i < length - 1 && s.charAt(i) == s.charAt(i + 1)) { 9 dp[i][i + 1] = true; 10 start = i; 11 maxLength = 2; 12 } 13 } 14 //计算回文长度是3-length 15 for(int strLength = 3; strLength <= length; strLength++) { 16 //计算所有长度为strLength的字符串是否是回文串 17 for(int i = 0; i <= length - strLength; i++) { 18 int j = i + strLength - 1;//子字符串终止位置 19 if(dp[i + 1][j - 1] == true && s.charAt(i) == s.charAt(j)) { 20 dp[i][j] = true; 21 start = i; 22 maxLength = strLength; 23 } 24 } 25 } 26 return s.substring(start, start + maxLength); 27 }
dp数组(例子:cabba计算回文):
0("c") | 1("a") | 2("b") | 3("b") | 4("a") | |
0("c") | T(c) | F(ca) | F(cab) | F(cabb) | F(cabba) |
1("a") | T(a) | F(ab) | F(abb) | T(abba) | |
2("b") | T(b) | T(bb) | F(bba) | ||
3("b") | T(b) | F(ba) | |||
4("a") | T(a) |
dp数组填充顺序:从左下到右上,即每一个数值计算都要用到左边,下边,左下的数据。
法三(借鉴):中心扩展法(分治法),以每个字符为中心,向两边扩展找相应的字符串是否有回文。但是,要注意两种情况,一种是aba的情况,一种是abba的情况,两种的扩展中心有点区别。代码如下(耗时67ms):
1 public String longestPalindrome(String s) { 2 int length = s.length(); 3 int start = 0, maxLength = 1; 4 //aba的情况,以i为中心扩展 5 for(int i = 0; i < length; i++) { 6 int left = i - 1, right = i + 1; 7 while(left >= 0 && right < length && s.charAt(left) == s.charAt(right)) { 8 if(right - left + 1 > maxLength) { 9 maxLength = right - left + 1; 10 start = left; 11 } 12 left--; 13 right++; 14 } 15 } 16 //abba的情况,以i, i+1为中心扩展 17 for(int i = 0; i < length; i++) { 18 int left = i, right = i + 1; 19 while(left >= 0 && right < length && s.charAt(left) == s.charAt(right)) { 20 if(right - left + 1 > maxLength) { 21 maxLength = right - left + 1; 22 start = left; 23 } 24 left--; 25 right++; 26 } 27 } 28 return s.substring(start, start + maxLength); 29 }