1. 程式人生 > >算法練習——最長回文子串

算法練習——最長回文子串

通過 輸出 new 復雜 isp -- 題目 否則 urn

題目:

給定一個字符串 s,找到 s 中最長的回文子串。

示例 1:

輸入: "babad"
輸出: "bab"
註意: "aba"也是一個有效答案。

示例 2:

輸入: "cbbd"
輸出: "bb"

方法1:暴力求解

思路:可以通從兩端到中間遍歷字符串,如果碰到字符串是回文串,則該回文串一定是是最長回文串。

效果:判斷的整個過程其實有三個內部循環,時間復雜度接近 O(n^3) ,空間復雜度O(n)

public class LongestPalindrome1 {
    
    //利用兩個for循環來遍歷所有的子串,並且在裏面再加一層while循環用於判斷字符串是否是回文串
public String longestPalindrome(String s) { for (int size = s.length(); size > 0; size--) { for (int low = 0, hight = low+size-1; hight < s.length(); low++,hight++) { if (isPalindrome(s,low,hight)) { return s.substring(low, hight+1); } } }
return s.substring(0, 1); } //判斷一個字符串是否是回文字符 private boolean isPalindrome(String s, int low, int hight) { while (low < hight) { if(s.charAt(low) == s.charAt(hight)){ low++; hight--; }else { return false; } }
return true; } }

方法2:動態規劃思想

思路:如果s(i,j)是回文串,則table[i][j] = true;否則定義為false。如何計算table[i][j]呢,我們可以首先檢查table[i+1][j-1]是否為true,及s[i]是否等於s[j]。

--------------------------------------------------這個思想其實和前面的求解最長公共子序列很像。

效果:時間復雜度O(n^2),空間O(n^2)

public class LongestPalindrome {
    public static String longestPalSubstr(String s){
        
        int n = s.length();
        
        boolean[][] table = new boolean[n][n];
        
        //所有的一個字符肯定是回文串
        int maxLength = 1;
        
        //組成的boolean矩陣的對角都肯定為true
        for (int i = 0; i < n; i++) {
            table[i][i] = true;
        }
        
        int start = 0;
        
        //如果字符串長度小於2,則直接處理
        for (int i = 0; i < n - 1; ++i) {
            if (s.charAt(i) == s.charAt(i +1)) {
                table[i][i+1] = true;
                start = i;
                maxLength = 2;
            }
        }
        
        //如果字符串長度大於2,則開始遍歷處理,主要是通過兩層for循環
        
        //檢查字符串長度大於2的字符串,其中k表示子字符串的長度
        for (int k = 3; k <= n; ++k) {
            
            //i表示子字符串中起始的位置
            for (int i = 0; i < n - k + 1; i++) {
                
                //獲取子字符串結束的位置,
                int j = i + k - 1;
                
                if (s.charAt(i) == s.charAt(j) && table[i+1][j-1]) {
                    table[i][j] = true;
                    if (k > maxLength) {
                        maxLength = k;
                        start = i;
                    }
                }
            }
        }
        return s.substring(start, start+maxLength);
    }    
}

方法3:分奇偶中心討論

思路:以某個元素為中心,分別計算偶數長度的回文最大長度和奇數長度的回文最大長度。

奇數有一個中心,偶數有兩個中心點,從中心點向兩端判斷,找出最長的回文子串。

效果:時間復雜度O(n^2),空間O(1)

public class LongestPalindrome {

    public static String longestPalSubstr(String s){
        //最後字符串的長度
        int maxLength = 1;  
        
        int start = 0;
        int len  = s.length();
        
        int low ,hight;
        
        
        //這裏面用i表示中心點的位置
        for (int i = 0; i < len; i++) {
            
            //首先查找最長的偶數回文字符串,有兩個中心點,分別為 i -1、 i
            low = i -1;
            hight = i;
            while (low >= 0 && hight < len && s.charAt(low) == s.charAt(hight)) {
                if (hight - low + 1 > maxLength) {
                    maxLength = hight - len + 1;
                    start = low;
                }
                --low;
                ++hight;
            }
            
            //其次尋找最長的奇數的最長回文字符串,中心點以i為主
            low = i - 1;
            hight = i + 1;
            while (low >= 0 && hight < len && s.charAt(low) == s.charAt(hight)) {
                if (hight - low + 1 > maxLength) {
                    maxLength = hight - low + 1;
                    start = low;
                }
                --low;
                ++hight;
            }
        }
        
        //起始和結束的位置
        return s.substring(start, start + maxLength);
    }
}

算法練習——最長回文子串