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     }
View Code

法二(借鉴):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     }
View Code

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     }
View Code
原文地址:https://www.cnblogs.com/cing/p/8471882.html