最長迴文子串問題(動態規劃 和machacher匹配)

1.動態匹配

  最長迴文子串 在一個字符串中 找到迴文字符串 ABCBA 就是一個迴文子串的形式;在最長迴文匹配問題上使用時間複雜度最短算法 o(N),相比於中心擴展法,不管長度是奇數還是偶數 使用manacher算法將其 全部情況轉換成 奇數進行處理。
      1.在每個字符的兩邊插入一個特殊符號 ABC----> #A#B#C#(奇數或者偶數字符串轉換成奇數的字符串)。
      2.藉助輔助數組P[i] 記錄以字符S[i] 爲中心的最長迴文的長度 ;id 表示p[1...j] 最大回文長度的位置,mx =id+p[id] 最大回文長度的邊界
根據macnacher算法--  p[i]>=min(p[2*id-i],mx-i)

3.如何進行遞推p[i] 矩陣:

    假設現在求出P[1,...i],現在需要求 後面的P[i+k] 的值,再假設現在有個指針k,從1循環到P[i] 
  出現之下的三種情況:
   如圖1所示:黑色部分是迴文子串,兩段紅色區間是對等相等的

   ①rad[i]-k<rad[i-k]: 
         rad[i-k] 的範圍是青色的部分,黑色的部分是迴文,且青色的部分超過了黑色的部分 radi+K]至少爲,即橙色的部分。那橙色以外的部分就不是了嗎?這是肯定的,因爲如果橙色以外的部分也是迴文的,那麼根據青色和紅色部分的關係,可以證明黑色部分再往外延伸一點也是一個迴文子串,這肯定是不可能的,所以 rad[i+k]=rad[i]-k;

②  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] 在最大回文長度之內。


 ③mx>i 但是P[i]>mx-i 如果s[i] 爲中心迴文子串超出邊界 (上述過程中1) 當p[i]>=mx-i, S[j]迴文子串不一定會完全被包含在 S[id]之內,
但是根據對稱性知道 P[i]>=mx-i 至於超出部分 必須要 i爲中心 在一一的進行匹配了。

④ mx<= i ;表示無法對P[i]做成很大的假設,即事實不在這個邊界 無法找到關於id位置對稱的點 上字符S[j] 與S[i]相等 只能讓p[i]=1;
// 動態規劃
		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();
	}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章