leetCode刷題之最長迴文子串

    乍一見這個題目,我的心是畏懼的。然後又生出必須要戰勝的決心。至於爲什麼感情如此豐富呢?主要還是因爲這道題曾經成爲我的一道坎坷。大一上學期學習C語言的時候,剛開始特別迷戀編程,天天刷題到圖書館關門。那時候真是一道題做一天正常的很(誇張誇張,不過半天確實有)。不過大一呀,正是玩樂的好時機,於是乎心慢慢鬆了。這道題卡了第55題,對於那時剛剛接觸編程才2個月的我當真麻煩的很,加上C語言指針什麼的,更是頭腦發熱。於是在半天思索還不見方案的前提下,我選擇了跳過這道題,繼續刷其他題。看起來情有可原,實際上卻是畏懼!哎哎哎。。。不說了。總之今天看到這道題,第一感覺就是征服,不僅要解決,還要用各種方法解決!

    不說了,晾題:

    

給定一個字符串 s,找到 s 中最長的迴文子串。你可以假設 長度最長爲1000。

示例:

輸入: "babad"

輸出: "bab"

注意: "aba"也是有效答案

    先說看到這道題目的思路吧,我的反應如下:

    1、將字符串s進行遍歷。

    2、判斷當前的節點是否符合迴文串條件,奇偶兩種情況。

    3、符合迴文串的像兩端擴展,並且添加到容器中。

    4、獲的list容器,存儲着所有的迴文串,和第一個字符(如果沒有2個或2個以上字符組成的迴文串,就以第一個字符爲最長迴文串計算)。

    5、對list進行排序,選取最長的迴文串作爲結果返回。

一下就是我首次的代碼:

    public static String longestPalindrome(String s) {
        //存儲不同長度的迴文串
        List<StringBuffer> sbList = new ArrayList<StringBuffer>();
        boolean isTwoCycle = false;
        boolean isThreeCycle = false;
        //默認將第一個字符傳入list,作爲默認最長迴文串
        sbList.add(new StringBuffer(String.valueOf(s.charAt(0))));
        for(int i = 1; i < s.length() ;i++){
            //判斷當前字符是否構成迴文串,是奇數還是偶數
            if(s.charAt(i) == s.charAt(i-1)){
                isTwoCycle = true;
            }
            if(i >= 2 && (s.charAt(i)==s.charAt(i-2))){
                isThreeCycle = true;
            }

            int cursor = 1;
            //如果是以兩個重複字爲迴文串
            if(isTwoCycle){
                //字符串下標不能小於0,同時不能超過字符串長度
                while(i-cursor>=0 && i+cursor-1<s.length()){
                    //符合迴文串規則
                    if(s.charAt(i-cursor) == s.charAt(i+cursor-1)){
                        cursor++;
                    }else{
                        break;
                    }
                }
                sbList.add(new StringBuffer(s.substring(i-cursor+1,i+cursor-1)));
                //可能該字符同時符合奇偶迴文串,如ccc,故分開置爲1
                cursor = 1;
                isTwoCycle = false;
            }
            //如果是以三個字,爲開始的迴文串,同時不能超過字符串長度
            if(isThreeCycle){
                while(i-cursor-1>=0 && i+cursor-1<s.length()){
                    if(s.charAt(i-cursor-1) == s.charAt(i+cursor-1)){
                        cursor++;
                    }else{
                        break;
                    }
                }
                sbList.add(new StringBuffer(s.substring(i-cursor,i+cursor-1)));
                cursor=1;
                isThreeCycle = false;
            }
        }

        Collections.sort(sbList, new Comparator<StringBuffer>() {
            @Override
            public int compare(StringBuffer sb1, StringBuffer sb2) {
                return -(sb1.length() - sb2.length());
            }
        });

        return sbList.get(0).toString();
    }

興沖沖地寫完,然後提交居然一次性成功,心裏竊喜還沒有停下,就突然蹦出一個134ms。納尼?134ms,仔細一看最快的,我去!7ms,神啊!有木有?心裏的竊喜馬上止住,趕忙打開7ms的代碼,那個簡潔,那個巧妙,那個精美……

    鄙人花了一些時間仔細看了一下代碼,然後自己書寫了一遍,如下:

/**
 * 可以看出,整個算法的核心主要有三點:
 *  1、將str字符串轉換成數組進行處理
 *  2、將偶迴文處理,使之變成奇迴文的處理方式(重)
 *  3、使用int[]數組,合理地記錄字符數組的下標,並以此來比較迴文串長度大小
 * Created by v_shampoowang on 2018/4/11.
 */
public class PalindromeString {
    public static void main(String[] args){
        System.out.println(new PalindromeString().
                longestPalindrome("aba"));
    }

    //求最長迴文子串
    public String longestPalindrome(String str){
        if(str.length()<=1) return  str;
        char[] characters = str.toCharArray();
        //用於存放str中最長迴文子串所對應的下標
        int[] range = {0,1};
        for(int i = 0;i<characters.length;i++){
            i = helper(i,characters,range);
        }
        return str.substring(range[0],range[1]);
    }

    private int helper(int index,char[] c,int[] range) {
        int low = index;
        int high = index;
        //如果遇到相同字符,則high進位,如abba ,這樣偶迴文子串也可以當做奇迴文處理了
        while(high<c.length-1 && c[high]==c[high+1]){
            high++;
        }
        int cursor = high;

        while(high+1<c.length&&low-1>=0&&c[low-1]==c[high+1]){
            low--;
            high++;
        }
        if(high-low+1>range[1]-range[0]){
            range[0] = low;
            range[1] = high + 1;
        }
        return cursor;
    }
}

    看完別人的代碼,此處不由得開始深思,我用了134ms!別人只用了7ms,近20倍的差距!仔細深析一下原因:

最大的原因肯定是自己考慮的點不對,未能能將多種處理方法歸併到一起,是積累不夠,也是敏感度地欠缺。

第二,變量使用率上不夠,很多變量的龐大,但是使用次數不多。

第三,產生了很多不必要的東西,比如list存儲了很多沒有必要的數據。

第四,儘量使用原生的數組,能夠將消耗變得最小,同時也能最大地提升效率。以前學C的時候就是使用數組,現在工作了一段時間,對容器的依賴加重了好多。

    總結:雖然自己現在的算法還不如很多大一學生,並且很多情況下對於我這個業務工程師來說,算法的精妙度體現不出來。但是算法的編寫又何嘗不是提升思維能力,提升學習興趣的過程。或許我現在只是一個業務工程師,但是說不定,幾年之後,我就像算法轉型了呢?就算不是,加深對數據結構和算法的理解,也是身爲一個程序員鎖必不可少的過程!

    在此互勉,共同進步。歡迎大家批評指正。

    

点赞