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