我的LC之路-5. Longest Palindromic Substring

Posted on 2017-11-22 09:45  泫辰  阅读(129)  评论(0)    收藏  举报

写在前面:在LeetCode上做的题,代码基本都是我自己写的,效率有好有坏,仅供参考。
有少数几道题苦思冥想做不出来的,可能会借鉴网上大神的解法,然后再自己编写,借鉴过他人解法的题会有说明。
本人不是算法出身,语言基本靠自学,有任何错误理解或者不当举措,还请各位大侠手下留情并不吝赐教!万分感谢~

题:

5. Longest Palindromic Substring

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example:

Input: "babad"

Output: "bab"

Note: "aba" is also a valid answer.

Example:

Input: "cbbd"

Output: "bb"

解题思路:

这道题想了挺久。。没有找到很好的解决方法。最开始使用两个for循环,从s.length开始慢慢缩短,然后进行判定是否是回文,但显而易见的超时了~

之后感觉怎么也跳不出双循环的黑洞。。。也是处于试探性的,既然从长到短不行,那试试从每个字符开始向前后扩散呢?

于是有了以下代码:

 

public class Solution {

    public String longestPalindrome(String s) {

        String ans = "";
        String temp;
        for(int i = 0;i<s.length();i++){
            temp = this.findPalindrome(s,i,i);
            if(temp.length()<this.findPalindrome(s,i,i+1).length()) temp = this.findPalindrome(s,i,i+1);
            if(ans.length()<temp.length()) ans = temp;
        }

        return ans;
    }

    public String findPalindrome(String s,int start,int end){

        while(start>=0&&end<s.length()&&s.charAt(start)==s.charAt(end)){
            start--;
            end++;
        }
        return s.substring(start+1,end);
    }
} 

这是对每个字符调用一次findPalindrome方法,这个方法就是从当前字符(或者是当前以及紧接着的下一个两个字符,因为aba和abba都是回文)开始向前向后同时对比,看看最长回文能延伸到哪,最后返回当前符合要求的回文。

每个字符需要经历两次调用,一次是单个字符,一次是当前和接下来的一个字符一起。在for循环中记录最长的回文,最后完成查找。LeetCode用时53ms,比最开始的两个for循环快了不少。

但运行结果显示我的成绩是40.89%,于是我看了下大神的杰作: 

class Solution {


  private int max_length;
  private int start;
  
  public String longestPalindrome(String input) {
    if(input == null || input.length() < 2) return input;
    char[] str = input.toCharArray();
    
    for(int i = 0; i < str.length;) {
      i = extendPalin(str, i);
    }
    return new String(str, start, max_length);
    
  }
  
  private int extendPalin(char[] str, int cursor) {
    int i = cursor, j = cursor;
    
    // For repetition, just skip and put in the middle of palindrome
    while(j < str.length - 1 && str[j] == str[j + 1]) j++;
    int skip = j + 1;
    
    while(i >= 0 && j < str.length && str[i] == str[j]) {
      i--; j++;
    }
    i++; j--;
    
    if(max_length < j - i + 1) {
      start = i;
      max_length = j - i + 1;
    }
    
    // return the index after skipping the duplicated entries to continue
    return skip;
  }
}

这是LeetCode上一个大神的答案,用时9ms。。。。。。简直粗暴,分析了下原理,大致上差不多,关键多了个skip变量。这个变量的作用是将一连串重复出现的字符跳过,举例说明:

例如传入的变量是“abcdddddcbefghj”按照我们的解法,是循环15次,对每个字符进行左右扩展。而加入了skip变量之后,在循环到第一个d字符时,会进行跳跃,使下一次循环直接从下标为8的c字符开始。这样做是因为,在一长串相同字符里,最长回文只可能出现在其中间位置,因此,再对其他位置的“d”进行判定的工作是多余的。