算法練習——最長回文子串
阿新 • • 發佈:2018-09-09
通過 輸出 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); } }
算法練習——最長回文子串