求最長迴文串

題目描述以下:html

 

能馬上想到的就是爆破,先試試無腦爆破,時間複雜度O(n^3),而後毫無心外的超時了,爆破代碼以下:java

public String longestPalindrome(String s) {
        
        int max = 0;
        int length = s.length();
        // 字符串長度只有1個或爲空,那麼它自身就是迴文串
        if (length <= 1) {
            return s;
        }
        
        String rtString = "";
        // 從第一個字符開始,統計以每一個字符開頭的能達到的最大回文子串
        for (int i = 0; i < length; i++) {
            for (int j = i + 1; j < length; j++) {
                
                String subStr = s.substring(i, j + 1);
                int left = 0;
                int right = subStr.length() - 1;
                boolean flag = true;
                // 判斷是否是迴文子串
                while (left <= right) {
                    if (subStr.charAt(left) == subStr.charAt(right)) {
                        left++;
                        right--;
                    }else {
                        flag = false;
                        break;
                    }
                }
                int size = subStr.length();
                // 進行最大長度記錄
                if (flag && size > max) {
                    max = size;
                    rtString = subStr;
                }
            }
        }
        
        if (max == 0) {
            rtString = s.charAt(0) + "";
        }
        
        return rtString;
}
View Code

 

而後思考怎麼使用動態規劃,無奈本人動態規劃渣渣,因而看題解算法

給出定義以下數組

那麼

P(i, j)=(P(i+1,j−1) and Si​==Sj​)

P(i,i)=true

P(i, i+1) = ( S_i == S_{i+1} )P(i,i+1)=(Si​==Si+1​)

 

恍然大悟,而後開始編碼,動態規劃算法代碼以下:ide

public String longestPalindrome1(String s) {
        
        if (s.length() <= 1) {
            return s;
        }
        
        int length = s.length();
        boolean[][] dp = new boolean[length][length];
        // 初始化單一字符爲迴文串
        for (int i = 0; i < dp.length; i++) {
            dp[i][i] = true;
        }
        
        // 由於dp[i][j]取決於d[i+1][j-1]的狀態,因此自底向上進行動態規劃
        for (int i = length - 1; i >= 0; i--) {
            for (int j = i; j < dp[i].length; j++) {
                if (j - i < 2) { //兩個字符相鄰或者就是同一個字符
                    dp[i][j] = (s.charAt(i) == s.charAt(j));
                }else { // 字符 i~j 是否爲迴文取決於 i+1 ~ j-1是否爲迴文 及 s[i] 是否等於 s[j]
                    dp[i][j] = (dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j));
                }
            }
        }
        
        // 遍歷dp數組找到最長迴文串
        int maxlength = 0;
        int maxi = 0;
        int maxy = 0;
        for (int i = 0; i < dp.length; i++) {
            for (int j = i; j < dp.length; j++) {
                if (dp[i][j]) {
                    int len = j - i + 1;
                    if (len > maxlength) {
                        maxlength = len;
                        maxi = i;
                        maxy = j;
                    }
                }
            }
        }
        
        return s.substring(maxi, maxy + 1);
    }
View Code

 

繼續看看還有什麼算法,看到中心擴展法,即以某個字符爲中心向兩邊擴展,時間複雜度爲O(n^2)代碼以下:編碼

public String longestPalindrome2(String s) {
        
        int length = s.length();
        if (length <= 1) {
            return s;
        }
        
        int max = 0;
        int startIndex = 0;
        // 這輪循環時計算
        for (int i = 0; i < length; i++) {
            
            int left = i;
            int right = i;
            
            // 求得迴文串長度爲奇數的串,返回值爲{迴文串串長度,迴文串開始下標}
            int[] jiCuan = getCuan(s, left, right);
            // 求得迴文串長度爲偶數的串,返回值爲{迴文串串長度,迴文串開始下標}
            int[] ouCuan = getCuan(s, left, right + 1);
            
            int bigger = 0;
            if (jiCuan[0] > ouCuan[0]) {
                bigger = jiCuan[0];
                left = jiCuan[1];
            }else {
                bigger = ouCuan[0];
                left = ouCuan[1];
            }
            
            if (bigger > max) {
                max = bigger;
                startIndex = left;
            }
        }
        return s.substring(startIndex, startIndex + max);
    }
    
    public int[] getCuan(String s, int left, int right) {
        // s[left](奇數迴文串時)或s[left]~s[right](偶數迴文串時)爲中心向兩邊擴展
        while (left >= 0 && right < s.length()) {
            if (s.charAt(left) == s.charAt(right)) {
                left--;
                right++;
            }else {
                break;
            }
        }
        // 循環退出以前會把left-1,right+1,因此分別要加回來和減出去
        left = left + 1;
        right = right - 1;
        int[] a = {right - left + 1, left};
        return a;
    }
View Code

 

還有一種算法,比較難想到,時間複雜度爲O(n),人稱「馬拉車算法」,這裏給出參考連接:spa

https://www.cnblogs.com/grandyang/p/4475985.html3d

相關文章
相關標籤/搜索