LeetCode(5) - Longest Palindromic Substring

  这道题要求的是给你一个string, 如“adcdabcdcba",要求返回长度最大的回文子字符串。这里有两个条件,一是子字符串,而是回文。用纯暴力搜索的话,需要用到O(n^3)的时间,必然超时。就算经过细节上的优化,它也有一个很长的test case不一定能过得去(说不一定是因为有时能过有时不能过),先贴上这个O(n^3)的代码,其实可以不用仔细看,面试用这种方法可不能过,所以大概了解一下就好,它只是对之后如何产生O(n^2)的代码做个铺垫,代码如下:

 1 public class Solution {
 2     public String longestPalindrome(String s) {
 3         int length = s.length();
 4         char[] charArray = new char[length];
 5         for (int i = 0; i < s.length(); i++) {
 6             charArray[i] = s.charAt(i);
 7         }
 8         int head = 0, tail = length - 1;
 9         int distance = 0;
10         for (int i = 0; i < length; i++) {
11             for (int j = length - 1; j > i; j--) {
12                 if (isPalindrome(charArray,i,j)) {
13                     if (j - i + 1 > distance) {
14                         head = i;
15                         tail = j;
16                         distance = j - i + 1;
17                         break;
18                     }
19                 }
20             }
21             if (distance >= length - i) break;
22         }
23         StringBuilder sb = new StringBuilder();
24         for (int i = head; i <= tail; i++) {
25             sb.append(charArray[i]);
26         }
27         return sb.toString();
28     }
29     
30     private boolean isPalindrome(char[] charArray,int head,int tail) {
31         while (head < tail) {
32             if (charArray[head++]!= charArray[tail--]) return false;
33         }
34         return true;
35     }
36 }

  我所采取的优化的方式是第二重循环是由后往前,碰到回文就跳出内循环(因为该回文一定是该循环里最长的循环),然后内循环结束后,如果最大的distance >= s.length() - i,说明外循环就没有必要继续再走下去(i继续增加,s.length() - i只会变小),可以直接break掉。这样子,在“运气”成份下,上述代码就存在了AC的情况。

  如果O(n^3)的方法不能够解决,那有没有O(n^2)的方法呢?经过思考我们可以发现,上述代码之所以是O(n^3),是因为辅助函数里还有一重循环O(n)。既然判断回文花费的时间一定是O(n),那么在主函数里,能不能只用一重循环呢?可以的。上面的代码判断回文是从两端往中间走,就是因为要确定两端才需要O(n^2)的时间,加上判断回文,那就是O(n^3)了。但如果我们是从中间往两端走呢?中间往两端走,判断回文虽然也需要O(n),但是确定中点,却只需要遍历一遍就够了,这样就能把主函数的二重循环变成一重循环了。

  当然,还要注意一些细节,从中间往外走,这个中点可能是单独一个其左右相同,也可能和相邻的相同再往外扩,这两种情况分开处理就好,需要的是维护两个数字,一个是回文字符串最长的长度maxLen,第二个是回文字符串开始的index。代码如下:

 1 //从中间开始走起的O(n^2)搜索。
 2 public class Solution {
 3     
 4     public String longestPalindrome(String s) {
 5         if (s.length() == 0 || s.length() == 1) return s;
 6         //数组里一个是maxLength,一个是最长回文字符串的head,每次都需要维护这个数组里的两个数。
 7         int[] res = new int[2];
 8         for (int i = 0; i < s.length(); i++) {
 9             //中点是单独存在的情况。
10             extendPalindrome(s,i,i,res);
11             //中点和相邻是相等的情况。
12             extendPalindrome(s,i,i+1,res);
13         }
14         int maxLength = res[0];
15         int head = res[1];
16         return s.substring(head,head + maxLength - 1);
17     }
18     
19     private void extendPalindrome(String s, int left, int right,int[] res) {
20         //left网左走,right往右走直到走到边界或者他们不是回文为止。
21         while (left >= 0 && right <= s.length() - 1) {
22             if (s.charAt(left) != s.charAt(right)) break;
23             left--;
24             right++;
25         }
26         int length = right - left;
27         if (length > res[0]) {
28             res[0] = length;
29             //+1是因为while循环里是在left=-1或者是回文边界的前一个跳出。
30             res[1] = left + 1;
31         }
32     }
33 }

  通过查阅Leetcode里面的discusion,发现还有一种O(n)的方法,这个方法运用的是Manacher's Algorithm,这种算法是一种非平凡算法,它需要用到O(n)的空间和O(n)的时间,在面试的过程中并不需要想出来(也想不到。。。),但是却是一个非常有意思的算法,下面的链接我觉得是对这个算法解释的比较清晰的一篇文章,有空可以去看看,研究研究:

  http://blog.csdn.net/insistgogo/article/details/12287805

  

转载于:https://www.cnblogs.com/kepuCS/p/5224625.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值