1.動態匹配
3.如何進行遞推p[i] 矩陣:
② rad[i] - k > rad[i - k]: rad[i+k]=rad[i-k];
如圖2,rad[i-k]的範圍爲青色,因爲黑色的部分是迴文的,且青色的部分在黑色的部分裏面,根據定義,很容易得出:rad[i + k] = rad[i - k]。根據上面兩種情況,可以得出結論:當rad[i] - k != rad[i - k]的時候,rad[i + k] = min(rad[i] - k, rad[i - k])。
③ rad[i] - k = rad[i - k]: 有可能比原來的長度要長 rad[i+k]>=rad[i-k];
如圖,通過和第一種情況對比之後會發現,因爲青色的部分沒有超出黑色的部分,所以即使橙色的部分全等,也無法像第一種情況一樣引出矛盾,因此橙色的部分是有可能全等的。但是,根據已知的信息,我們不知道橙色的部分是多長,因此就需要再去嘗試和判斷了。
之上理解 告訴macnacher算法的 迴文最大長度的邊界 與 新增入的p[i] 的位置關係 ,根據July的編程之法的理解中
id 表示最大回文長度的位置 ,求p[i]位置的值 假設已經知道p[0,1...i-1]的值
mx 表示id+p[id] :最大回文長度的邊界
① 根據對稱性 求出 i關於id 位置的 對稱點 j=id-(i-id)=2id-i; 總共分爲 mx>i 和mx<=i
② 當mx>i: 同時候 mx-i>p[i] 說明以s[j]爲中心迴文子串的包含在S[id]爲中心的迴文子串中 ,i與j對稱
以s[i]爲中心迴文子串的包含在S[id]爲中心的迴文子串中對應上述過程中2 過程 S[i] 在最大回文長度之內。
// 動態規劃 for(int len=2;len<=length;len++)// len 表示迴文字符串長度,i表示迴文子串初始位置 for(int i=0;i<length-len+1;i++) { int j=i+len-1;//子串的結束位置 if(p[i+1][j-1] && str.charAt(i)==str.charAt(j)) { p[i][j]=true; maxlength=len; start=i; } } if(maxlength>=2) return str.substring(start,maxlength); return null; } // 中心擴展法,迴文的話,那麼 其中心位置 前綴和後綴一定是相等,枚舉 所有的中心位置 public static String findLongestOalindrome1(String str) {// 字符串是從 0 位置開始進行索引 if(str==null) return null; int start=0;int max=0; int i,j,c = 0;int n=str.length(); for( i=0;i<str.length();++i) { // 處理奇數 以 i爲中心,向兩邊擴展 for(j=0;(i-j)>=0 &&(i+j)<n;++j) { if(str.charAt(i-j)!=str.charAt(i+j)) { break;} c=2*j+1; } if(c>max) { max=c; start=i-j+1; } // 處理偶數abba 明顯i=b,j=0 判斷 i-j(本身) 與 i+j+1(i+1) for(j=0;(i-j)>=0 &&(i+j+1)<n;++j) { if(str.charAt(i-j)!=str.charAt(i+j+1)) {break;} c=2*j+2; } if(c>max) { max=c; start=i-j+1; } } System.out.println(start); return str.substring(start, max); } public static String findLongestOalindrome2(String str) { if(str == null||str.length() == 0) return str; StringBuilder sb=new StringBuilder(); sb.append('#'); for(int i=0;i<str.length();i++) { sb.append(str.charAt(i)); sb.append('#'); } str=sb.toString(); int n=str.length(); // Manancher id 表示P[i] 最大回文子串位置 mx =max(p[i])+id 最大回文子串的邊界 int id=0,mx=0,i; int p[]=new int[str.length()]; // 從左往右遍歷 str ,對於 i位置現已經知曉 p[0,1...i-1]中的值 for( i=1;i<str.length();i++) { if(mx>i) { p[i]=Math.min(p[2*id-i],mx-i); } else { p[i]=1; } // p[i]>=mx-i while( i+p[i]<n &&i-p[i]>=0&&str.charAt(i+p[i])==str.charAt(i-p[i])) p[i]++; if(p[i]+i>mx) { mx=p[i]+i; id=i; } } /*****進行輸出 找到P[i]最大值所對應的位置就是 最大回文子串位置**/ int max=0; for( i=1;i<p.length;i++) { if(p[i]>max) { max=p[i]; id=i; } } int start=id-max+1; int end=id+max-1; StringBuilder sb2=new StringBuilder(); for( i=start;i<=end;i++) { if(str.charAt(i)!='#') sb2.append(str.charAt(i)); } return sb2.toString(); }