1. 程式人生 > >Java 實現求最長迴文子串

Java 實現求最長迴文子串

下面以字串12212321為例,經過上一步,變成了 S[] = "$#1#2#2#1#2#3#2#1#";

然後用一個數組 P[i] 來記錄以字元S[i]為中心的最長迴文子串向左/右擴張的長度(包括S[i],也就是把該回文串“對摺”以後的長度),比如S和P的對應關係:

S  #  1  #  2  #  2  #  1  #  2  #  3  #  2  #  1  #
P  1  2  1  2  5  2  1  4  1  2  1  6  1  2  1  2  1
(p.s. 可以看出,P[i]-1正好是原字串中迴文串的總長度)
那麼怎麼計算P[i]呢?該演算法增加兩個輔助變數(其實一個就夠了,兩個更清晰)id和mx,其中 id 為已知的 {右邊界最大} 的迴文子串的中心,mx則為id+P[id],也就是這個子串的右邊界。


然後可以得到一個非常神奇的結論,這個演算法的關鍵點就在這裡了:如果mx > i,那麼P[i] >= MIN(P[2 * id - i], mx - i)。就是這個串卡了我非常久。實際上如果把它寫得複雜一點,理解起來會簡單很多: //記j = 2 * id - i,也就是說 j 是 i 關於 id 的對稱點(j = id + (id - i))
if (mx - i > P[j]) 
    P[i] = P[j];
else /* P[j] >= mx - i */
    P[i] = mx - i; // P[i] >= mx - i,取最小值,之後再匹配更新。
當然光看程式碼還是不夠清晰,還是藉助圖來理解比較容易。


當 mx - i > P[j] 的時候,以S[j]為中心的迴文子串包含在以S[id]為中心的迴文子串中,由於 i 和 j 對稱,以S[i]為中心的迴文子串必然包含在以S[id]為中心的迴文子串中,所以必有 P[i] = P[j],見下圖。
點選在新視窗中瀏覽此圖片

當 P[j] >= mx - i 的時候,以S[j]為中心的迴文子串不一定完全包含於以S[id]為中心的迴文子串中,但是基於對稱性可知,下圖中兩個綠框所包圍的部分是相同的,也就是說以S[i]為中心的迴文子串,其向右至少會擴張到mx的位置,也就是說 P[i] >= mx - i。至於mx之後的部分是否對稱,就只能老老實實去匹配了。
點選在新視窗中瀏覽此圖片

對於 mx <= i 的情況,無法對 P[i]做更多的假設,只能P[i] = 1,然後再去匹配了。


於是程式碼如下: //輸入,並處理得到字串s
int p[1000], mx = 0, id = 0;
memset(p, 0, sizeof(p));
for (i = 1; s[i] != '\0'; i++) {
    p[i] = mx > i ? min(p[2*id-i], mx-i) : 1;
    while (s[i + p[i]] == s[i - p[i]]) p[i]++;
    if (i + p[i] > mx) {
        mx = i + p[i];
        id = i;
    }
}
//找出p[i]中最大的
Java 程式碼如下: package Exercises;


import java.io.FileNotFoundException;
import java.util.Scanner;


public class Palindrome {


public static void main(String[] args) throws FileNotFoundException{
// TODO Auto-generated method stub
 int caseNum = 0;
     Scanner sc = new Scanner(System.in);
       while (true) {
           String str = sc.nextLine();
           if (str.equals("END")) {
               break;
           } else {
               caseNum ++;
               System.out.println("Case " + caseNum + ": " + getLongestPalindrome(str));
           }
       }
}
 public static int getLongestPalindrome(String A) {
       // write code here
            // 1.構造新的字串
       // 為了避免奇數迴文和偶數迴文的不同處理問題,在原字串中插入'#',將所有迴文變成奇數迴文
       StringBuilder newStr = new StringBuilder();
       newStr.append('#');
       for (int i = 0; i < A.length(); i ++) {
           newStr.append(A.charAt(i));
           newStr.append('#');
       }
       // p[i]表示以i為中心的迴文的最大半徑,i至少為1,即該字元本身
       int [] p = new int[newStr.length()];
       // mx表示已知的迴文中,最右的邊界的座標
       int mx = -1;
       // id表示已知的迴文中,擁有最右邊界的迴文的中點座標
       int id = -1;
       // 2.計算所有的p
       // 這個演算法是O(n)的,因為mx只會隨著裡層while的迭代而增長,不會減少。
       for (int i = 0; i < newStr.length(); i ++) {
           // 2.1.確定一個最小的半徑
           int r = 1;
           if (i <= mx) {
               r = Math.min(p[id] - i + id, p[2 * id - i]);
           }
           // 2.2.嘗試更大的半徑
           while (i - r >= 0 && i + r < newStr.length() && newStr.charAt(i - r) == newStr.charAt(i + r)) {
               r++;
           }
           // 2.3.更新邊界和迴文中心座標
           if (i + r - 1> mx) {
               mx = i + r - 1;
               id = i;
           }
           p[i] = r;
       }
       
       // 3.掃描一遍p陣列,找出最大的半徑
       int maxLength = 0;
       for (int r : p) {
           if (r > maxLength) {
               maxLength = r;
           }
       }
       return maxLength - 1;
   }
}

相關推薦

Java 實現

下面以字串12212321為例,經過上一步,變成了 S[] = "$#1#2#2#1#2#3#2#1#";然後用一個數組 P[i] 來記錄以字元S[i]為中心的最長迴文子串向左/右擴張的長度(包括S[i],也就是把該回文串“對摺”以後的長度),比如S和P的對應關係: S 

java

一開始看到這個題目的時候,我就想到了第一種思路: (1)從頭遍歷每個字元,從該字元向兩邊擴充套件,直到字串最長界限或者兩邊擴充套件的字元不相等為止,記錄每個字元搜尋的長度,並且找最大的即為最長迴文子串個數。演算法優化的地方(當一個字元的擴充套件長度為整個字串長度時候,停止搜

java

/** * 求最長迴文子串 * 子串:連續的 * 暴力窮舉 */ public static String get01() { Stri

Manacher演算法------Java)

最長迴文子串 對於一個字串,請設計一個高效演算法,計算其中最長迴文子串的長度。 給定字串A以及它的長度n,請返回最長迴文子串的長度。 測試樣例: "abc1234321ab",12 返回:7 public class Main {      public st

_Manacher演算法_Java實現

通過對大神C程式碼的分析學習,結合自身理解,留下自己的Java實現過程。 原文: http://blog.csdn.net/xingyeyongheng/article/details/9310555 Manacher演算法求最長迴文子串,其時間複雜度幾乎是o(n),利用迴

【HDU - 3068】(Manacher演算法,馬拉車演算法

題幹: 給出一個只由小寫英文字元a,b,c...y,z組成的字串S,求S中最長迴文串的長度.  迴文就是正反讀都是一樣的字串,如aba, abba等 Input 輸入有多組case,不超過120組,每組輸入為一行小寫英文字元a,b,c...y,z組成的字串S  兩

馬拉車演算法()

1 #include <vector> 2 #include <iostream> 3 #include <string> 4 5 using namespace std; 6 7 string Manacher(string s) {

動態規劃1.

求字串的子串大致有四中方法,暴力,DP,中心拓展,馬拉車演算法,這篇講DP怎麼做。 DP最重要的就是要能利用到前面的結果來推斷當前狀態,比暴力優化的地方就在此,暴力需要對每一個字串做一次O(n)的操作才能判斷出結果,也就是整個過程要O(n^3),但DP對每一個字串的判斷時間是O(1),總共是O(n^2)

【Manacher模板】HDU 3068——

直接做會超時,需要優化,網上通行的演算法是manacher演算法(具體原理還不是很明白),這裡可以當模板使。 // 原串最大長度N // 返回最大回文字串 res #include<cstdio> #include<cstring> #includ

(多種解法)

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest

O(n)的方法長度(Manacher演算法)

大體思路其實就是找出一箇中心點,判斷中心點兩端的迴文串半徑是多少; 但由於找中心點的方法只適用於奇數長的迴文串,故可以在每兩個字元間插入一個間隔符來幫助結算; 用rd[i]表示以經過填充後的字串裡的第i個字元為中心,它的迴文串長度; 可以得知,在【

--演算法思想探討和實現(python java)

最長迴文子串–演算法思想探討和實現(python java) 迴文串定義: 如果一個字串正著讀和反著讀是一樣的,那它就是迴文串。 下面是一些迴文串的例項: 12321 a aba abba aaaa tattarrattat 問題定義 最長迴

java實現:查詢字串中 ---- leetCode notes

Given a string s, find the longest palindromic substring in s. You may assume that the maximum len

LeetCode 5(java程式碼)

方法一:動態規劃       定義P(i,j):如果字串從i位置到j位置是迴文,P(i,j)=true;否則,P(i,j)=false;      那麼P(i,j)= P(i+1,j−1) && Si==Sj &

leetcode-5-(longest palindromic substring)-java

題目及測試 package pid005; /*最長迴文子串 給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。 示例 1: 輸入: "babad" 輸出: "bab" 注意: "aba"也是一個有效答案。 示例 2: 輸入: "cbbd" 輸出:

go實現

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為 1000。 示例 1: 輸入: "babad" 輸出: "bab" 注意: "aba" 也是一個有效答案。 示例 2: 輸入: "cbbd" 輸出: "bb" func longestPalindrome(s st

演算法題:(C#實現

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為 1000。 示例 1: 輸入: "babad" 輸出: "bab" 注意: "aba" 也是一個有效答案。 示例 2: 輸入: "cbbd" 輸出: "bb

領釦--數和--Python實現

判斷一個整數是否是迴文數。迴文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。 示例 1: 輸入: 121 輸出: true 示例 2: 輸入: -121 輸出: false 解釋: 從左向右讀, 為 -121 。 從右向左讀, 為 121- 。因此它不是一個迴文數。 示例 3:

leetcode--JAVA

一.題目給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。示例 1:輸入: "babad" 輸出: "bab" 注意: "aba"也是一個有效答案。 示例 2:輸入: "cbbd" 輸出: "bb示例 2:二.解題思路從1到字串長度開始遍歷,

【Leetcode】Python實現

動態規劃實現 根據迴文的特性,一個大回文按比例縮小後的字串也必定是迴文,比如ABCCBA,那BCCB肯定也是迴文。所以我們可以根據動態規劃的兩個特點: (1)把大問題拆解為小問題 (2)重複利用之