KMP演算法分析 java

2021-09-24 20:41:12 字數 3446 閱讀 2696

如果用暴力匹配的思路,並假設現在str1匹配到 i 位置,子串str2匹配到 j 位置,則有:

如果當前字元匹配成功(即str1[i] == str2[j]),則i++,j++,繼續匹配下乙個字元

如果失配(即str1[i]! = str2[j]),令i = i - (j - 1),j = 0。相當於每次匹配失敗時,i 回溯,j 被置為0。

用暴力方法解決的話就會有大量的回溯,每次只移動一位,若是不匹配,移動到下一位接著判斷,浪費了大量的時間。(不可行!)

暴力匹配演算法實現.

package com.atguigu.kmp;

public class violencematch

// 暴力匹配演算法實現

public static int violencematch(string str1, string str2) else

} //判斷是否匹配成功

if(j == s2len) else

}}

上面是暴力演算法都是一步步的移動的,時間複雜度 

其實大體kmp歸結於:第一步找出公共部分子字串字首字尾公共部分,形成next陣列,第二部根據next陣列移動,其實所謂的移動就是移動子字串首字母與比較的字串裡的對應字母位置這樣跳轉。

第一步是尋找字首字尾最長公共元素長度:字首不包含最後乙個元素,字尾不包含第乙個函式,運用高中知識集合來排列出來,

如果給定的模式串是:「abcdabd」,從左至右遍歷整個模式串,其各個子串的字首字尾分別如下**所示:

也就是說我們找字首和字尾公共部分有多少,原模式串子串對應的各個字首字尾的公共元素的最大長度表為

因為模式串中首尾可能會有重複的字元,故可得出下述結論:失配時,模式串向右移動的位數為:已匹配字元數 - 失配字元的上一位字元所對應的最大長度值。

下面,咱們就結合之前的《最大長度表》和上述結論,進行字串的匹配。如果給定文字串「bbc abcdab abcdabcdabde」,和模式串「abcdabd」,現在要拿模式串去跟文字串匹配,如下圖所示:

1. 因為模式串中的字元a跟文字串中的字元b、b、c、空格一開始就不匹配,所以不必考慮結論,直接將模式串不斷的右移一位即可,直到模式串中的字元a跟文字串的第5個字元a匹配成功:

2. 繼續往後匹配,當模式串最後乙個字元d跟文字串匹配時失配,顯而易見,模式串需要向右移動。但向右移動多少位呢?因為此時已經匹配的字元數為6個(abcdab),然後根據《最大長度表》可得失配字元d的上一位字元b對應的長度值為2,所以根據之前的結論,可知需要向右移動6 - 2 = 4 位。

3. 模式串向右移動4位後,發現c處再度失配,因為此時已經匹配了2個字元(ab),且上一位字元b對應的最大長度值為0,所以向右移動:2 - 0 =2 位。

4. a與空格失配,向右移動1 位。

5. 繼續比較,發現d與c 失配,故向右移動的位數為:已匹配的字元數6減去上一位字元b對應的最大長度2,即向右移動6 - 2 = 4 位。

6. 經歷第5步後,發現匹配成功,過程結束。

通過上述匹配過程可以看出,問題的關鍵就是尋找模式串中最大長度的相同字首和字尾,找到了模式串中每個字元之前的字首和字尾公共部分的最大長度後,便可基於此匹配。而這個最大長度便正是next 陣列要表達的含義。

由上文,我們已經知道,字串「abcdabd」各個字首字尾的最大公共元素長度分別為:

而且,根據這個表可以得出下述結論

失配時,模式串向右移動的位數為:已匹配字元數 - 失配字元的上一位字元所對應的最大長度值

上文利用這個表和結論進行匹配時,我們發現,當匹配到乙個字元失配時,其實沒必要考慮當前失配的字元,更何況我們每次失配時,都是看的失配字元的上一位字元對應的最大長度值。如此,便引出了next 陣列。

給定字串「abcdabd」,可求得它的next 陣列如下:

把next 陣列跟之前求得的最大長度表對比後,不難發現,next 陣列相當於「最大長度值」 整體向右移動一位,然後初始值賦為-1。意識到了這一點,你會驚呼原來next 陣列的求解竟然如此簡單:就是找最大對稱長度的字首字尾,然後整體右移一位,初值賦為-1(當然,你也可以直接計算某個字元對應的next值,就是看這個字元之前的字串中有多大長度的相同字首字尾)。

換言之,對於給定的模式串:abcdabd,它的最大長度表及next 陣列分別如下:

根據最大長度表求出了next 陣列後,從而有

失配時,模式串向右移動的位數為:失配字元所在位置 - 失配字元對應的next 值

而後,你會發現,無論是基於《最大長度表》的匹配,還是基於next 陣列的匹配,兩者得出來的向右移動的位數是一樣的。為什麼呢?因為:

/**

* @author 江河

* @date 2019-06-28 10:55

*/public class kmpalogrithm

int res = kmp.indexof(b, a);

system.out.println(res);

} public int indexof(string source, string pattern) else

}if (j == plen)

return i - j;

return -1;

} /**

* 下面是實現部分

* @param p

* @return

*/public int getnext(char p) else

}return next;

}}

這裡部落格是講解最詳細的,就是感覺太詳細太多了

KMP演算法分析

根據博主july的所載,記錄個人理解心得 紅色部分為個人理解 1.kmp演算法流程 假設現在文字串s匹配到 i 位置,模式串p匹配到 j 位置 1.如果j 1,或者當前字元匹配成功 即s i p j 都令i j 繼續匹配下乙個字元 當s i p j 時,說明模式串j前面的字元都與文字串i前面對應的字...

Java實現KMP演算法

對於查詢字元子串在父字串中出現的位置,我們可以使用kmp演算法。kmp演算法的實現原理是使子串向右滑盡可能的遠,這就涉及到求滑動距離的陣列next.next陣列中每個元素求解的公式是 private static void kmpnext int next,string str 這裡需要附加說明的是...

kmp演算法 java實現

通常我們想在乙個字串中匹配乙個子字串,會遍歷字串,對於每乙個字元,都遍歷子字串進行匹配,這樣時間複雜度為o nm 使用kmp演算法只需先進行乙個o m 的預處理 生成next陣列 就能將搜尋的時間複雜度降低至o n m 下面講一講kmp演算法的實現原理。對於abcdeabd.和abcdeabc,當匹...