KMP演算法-Java實現

來源:互聯網
上載者:User

標籤:解決   length   false   ati   next數組   string   while   return   log   

目的:

為瞭解決字串模式比對

曆程:

樸素模式比對:逐次進行比較

KMP演算法:利用匹配失敗得到的資訊,來最大限度的移動模式串,以此來減少比較次數提高效能

概念:

m:是目標串長度

n:是模式串長度

j:某次匹配時,第一次出現的不同的索引位置(有的稱為:失配位

k:最長首尾串長度(有的稱為:最長公用前尾碼

核心思想:

S   S0 S1 ...... Si-j-1 Si-j Si-j+1 Si-j+2 ...... Si-2 Si-1 Si ...... Sn-1

                              ||     ||      ||            ||   ||   ×

P                            P0    P1      P2              Pj-2 Pj-1 Pj

有Si-j-1Si-jSi-j+1 Si-j+2 ...... Si-2 Si-1=P0P1 P2 ...... Pj-2 Pj-1

如果  P0P1 P2 ...... Pj-2 ≠ P1 P2 ...... Pj-2Pj-1

則可以立即斷定 P0P1 P2 ...... Pj-2 ≠ Si-j+1 Si-j+2 ...... Si-2 Si-1,即:樸素模式比對的下一次移動一定不匹配,則可以跳過這一次

如果  P0P1 P2 ...... Pj-3 ≠ P2 ...... Pj-2Pj-1

則可以立即斷定 P0P1 P2 ...... Pj-2 ≠ Si-j+1 Si-j+2 ...... Si-2 Si-1,即:樸素模式比對的下一次移動一定不匹配,則可以跳過這一次

直到第一次出現相等的情況終止:P0P1 P2 ...... Pk-1 = Pj-k ...... Pj-2Pj-1

得到的k就是最長的首尾串長度,然後通過 j-k 得到了我們需要移動的位元,這樣我們就利用了匹配失敗的結果,得到了我們可以移動的步數,提升了效能

關於k:

其實肉眼就直接能看出來,k是最長首尾串長度,比如:

11111 k=4(首碼:1111,尾碼:1111)

12112 k=2(首碼:12,尾碼:12)

12345 k=0(無相同首碼尾碼)

例子:

S=ababababababb

P=abababb

重申一下原理:樸素模式比對效率低的原因是一位一位的比較,丟棄了之前失敗的資訊。而KMP演算法從匹配失敗的資訊中得到可以最大移動的步數,以此來減少比較的次數,來提升效能。

這裡並沒有提及,next數組及newnext數組,模式串的特徵向量N,其實不用管它,思想理解了,只是別人起了個叫法而已。

Java代碼:

    /**     * 樸素模式比對     *      * @param source 目標串     * @param pattern 模式串     */    private static void plain(String source, String pattern) {        int res=0;        int sourceLength=source.length();        int patternLength=pattern.length();        for(int i=0;i<=(sourceLength-patternLength);i++){            res++;            String str=source.substring(i, i+patternLength);            if(str.equals(pattern)){                p("樸素模式:匹配成功");                break;            }        }        p("樸素模式:一共匹配"+res+"次數");    }
    //KMP演算法實現
   private static void KMP(String source, String pattern) { int[] N=getN(pattern); int res=0; int sourceLength=source.length(); int patternLength=pattern.length(); for(int i=0;i<=(sourceLength-patternLength);){ res++; String str=source.substring(i, i+patternLength);//要比較的字串 p(str); int count=getNext(pattern, str,N); p("移動"+count+"步"); if(count==0){ p("KMP:匹配成功"); break; } i=i+count; } p("KMP:一共匹配"+res+"次數"); } /** * 得到下一次要移動的次數 * * @param pattern * @param str * @param N * @return 0,字串匹配; */ private static int getNext(String pattern,String str,int[] N) { int n = pattern.length(); char v1[] = str.toCharArray(); char v2[] = pattern.toCharArray(); int x = 0; while (n-- != 0) { if (v1[x] != v2[x]){ if(x==0){ return 1;//如果第一個不相同,移動1步 } return x-N[x-1];//x:第一次出現不同的索引的位置,即j } x++; } return 0; } private static int[] getN(String pattern) { char[] pat=pattern.toCharArray(); int j=pattern.length()-1; int[] N=new int[j+1]; for(int i=j;i>=2;i--){ N[i-1]=getK(i,pat); } for(int a:N) p(a); return N; } private static int getK(int j, char[] pat) { int x=j-2; int y=1; while (x>=0 && compare(pat, 0, x, y, j-1)) { x--; y++; } return x+1; } private static boolean compare(char[] pat,int b1,int e1,int b2,int e2){ int n = e1-b1+1; while (n-- != 0) { if (pat[b1] != pat[b2]){ return true; } b1++; b2++; } return false; } public static void p(Object obj) { System.out.println(obj); }

next數組:

KMP能提高效能原因是減少了比較次數,也就是知道k

而k從只和j有關,這就意味著移動的次數只和模式串有關,和目標串無關

簡單來說,就是我們得到模式串後就能立馬知道移動的次數,這就是next數組。裡面儲存的就是k值。

 

KMP演算法-Java實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.