1. 程式人生 > >KMP演算法-Java實現

KMP演算法-Java實現

目的:

為了解決字串模式匹配

歷程:

樸素模式匹配:逐次進行比較

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

概念:

m:是目標串長度

n:是模式串長度

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

k:最長首尾串長度(有的稱為:最長公共前後綴

核心思想:

S   S0 S...... 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實現

package algorithm; public class KmpSearch { public static void main(String[] args) { String s1 = "ABABCABAA"; char[] pattern = s1.to

KMP演算法-Java實現

目的: 為了解決字串模式匹配 歷程: 樸素模式匹配:逐次進行比較 KMP演算法:利用匹配失敗得到的資訊,來最大限度的移動模式串,以此來減少比較次數提高效能 概念: m:是目標串長度 n:是模式串長度 j:某次匹配時,第一次出現的不同的索引位置(有的稱為:失配位) k:最長首尾串長度(有的稱為:最長公共前後綴)

基本排序演算法-java實現

最近重新學習了排序演算法,之前每次看完當時理解了,但是過一段時間就又忘了,尤其是程式碼,如果放一段時間有很多base case不知道怎麼寫了,所以還是應該詳細的解讀一下再不斷了敲程式碼才能理解比較深刻。 1.氣泡排序(bubble sort) 氣泡排序是一種簡單的排序演算法。其基本思

python資料結構之KMP演算法實現

我相信網上已經有很多關於KMP演算法的講解,大致都是關於部分匹配表的實現思路和作用,還有就是目標串的下標不變,僅改變模式串的下標來進行匹配,確實用KMP演算法,當目標串很大模式串很小時,其效率很高的,但都是相對而言。至於對於部分匹配表的作用以及實現思路,建議看一下這篇文章寫的是比較易懂的

編輯距離演算法Java實現

/** * 計算編輯距離Edit Distance * if i == 0 且 j == 0,edit(i, j) = 0 * if i == 0 且 j > 0,edit(i, j) = j * if i > 0 且j == 0,edit(i,

分散式ID 雪花演算法JAVA實現

少年不想寫,來吧:https://github.com/singgel/SnowFlake snowflake的結構如下(每部分用-分開): 概述 分散式系統中,有一些需要使用全域性唯一ID的場景,這種時候為了防止ID衝突可以使用36位的UUID,但是UUID有一些缺點,首先他相對比

氣泡排序演算法java實現

package algorithm; /** * 氣泡排序演算法 * @author su * */ public class BubbleSort { public static void main(String[] args) { int[] a = {6,2,5,4,7,1,

0-1揹包問題—回溯演算法java實現

0-1揹包問題 【問題描述】 有n種可選物品1,…,n ,放入容量為c的揹包內,使裝入的物品具有最大效益。 表示 n :物品個數 c :揹包容量 p1,p2, …, pn:個體物品效益值 w1,w2, …,wn:個體物品容量 【問題解析】 0-1揹包問題的解指:物品1,…,n的一種放

推特雪花演算法 java實現

package twiter.snowflake; /** * twitter的snowflake演算法 -- java實現 */ public class SnowFlake { /** * 起始的時間戳 */ private final static long

最小生成樹Prim演算法java實現

package prim; import java.util.*; public class PrimTest { public static void main(String[] args) { //互動輸入圖的鄰接矩陣表示,為方便測試,直接給定了鄰接矩陣值 // System

Dijkstra演算法-Java實現

給定n個城市,並建立一個n*n的距離矩陣來存放兩兩城市之間的距離,當兩個城市之間不能直達時,將距離記為無窮大。對矩陣進行初始化: for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) {

反轉連結串列演算法Java實現

之前遇到反轉連結串列的演算法,比較晦澀難解,但其實挺簡單的。 目標:將一個順序連結串列反轉。 思路:用三個輔助節點,每次實現一個節點的指向反轉,即他的後繼變為他的前驅。           三個輔助節點: p  q  r&n

【資料結構與演算法-java實現】二 複雜度分析(下):最好、最壞、平均、均攤時間複雜度的概念

上一篇文章學習了:如何分析、統計演算法的執行效率和資源消耗? 點選連結檢視上一篇文章:複雜度分析上 今天的文章學習以下內容: 最好情況時間複雜度 最壞情況時間複雜度 平均情況時間複雜度 均攤時間複雜度 1、最好與最壞情況時間複雜度 我們首先

6種排序演算法java實現

6種排序演算法 氣泡排序 選擇排序 插入排序 計數排序 快速排序 歸併排序 1)氣泡排序       相鄰的兩個數字比較排序,先將最大的交換到最後面,然後重複。 程式碼實現 2)選擇排序       從第一個位置開始,用某個位置依次與後邊所有元

連結串列排序演算法java實現(連結串列的快速排序、插入排序、歸併排序)

難易程度:★★ 重要性:★★★      連結串列的排序相對陣列的排序更為複雜些,也是考察求職者是否真正理解了排序演算法(而不是“死記硬背”) 連結串列的插入排序 public class LinkedInsertSort { static cla

經典排序演算法java 實現

排序演算法的好壞對於效率的影響十分顯著。好的排序演算法排序100萬個整數可能只需要一秒(不考慮硬體因素),不好的排序演算法可能需要一個小時甚至幾個小時。 常見的排序演算法有氣泡排序、插入排序、堆排序、快速排序等,這些排序都屬於基於比較的排序,因此這些演算法的時間

Dijkstra演算法 java實現

import java.util.HashMap; import java.util.HashSet; import java.util.Map.Entry; /** * * Dijkstra演算法 * 適用範圍:沒有權值為負數的邊 * */ // no ne

常見排序演算法Java實現

目前最經典的排序演算法要屬:氣泡排序,快速排序,簡單插入排序,希爾排序,簡單選擇排序,堆排序,二路歸併排序,多路鬼 並排序,計數排序,桶排序,基數排序。以下就是這些常見演算法的Java實現,有興趣的可以自行實現。現在我們就來一個個分析 介紹一下各自的基礎思想和實現。講解這些演

有權最短路徑問題:狄克斯特拉(Dijkstra)演算法 & Java 實現

一、有權圖 之前我們知道,在無權重的圖中,求兩個頂點之間的最短路徑,可以使用 廣度優先搜尋 演算法。但是,當邊存在權重(也可以理解為路程的長度)時,廣度優先搜尋不再適用。 針對有權圖中的兩點間最短路徑,目前主要有 狄克斯特拉演算法 和 貝爾曼福德演算法 兩種解決

MD5演算法java實現原始碼

流程 處理需要加密的字串: 以byte[]的形式獲取,此時,每個字元為一個位元組,佔8位 當此時獲得的位元組流對512位,也就是64個位元組取餘,結果不為448,即56個位元組時,使用1000……0的二進位制位進行補位,直到取餘結果為448,;而當結果為448時