[牛客算法系列] KMP演算法
阿新 • • 發佈:2019-02-02
題目
- 給定兩個字串source 和 match, 長度分別為 N 和 M。實現一個演算法,如果字串source 中,含有子串match, 則返回match 在 source 中的開始為位置,不含有返回-1.
- 舉例
source = “acbc”, match = “bc” , 返回2.
source = “acbc”, match = “bcc” , 返回-1; - 要求,如果match 的長度大於source 的長度(M > N)source 必然不會含有match, 可直接返回-1。但如果N >= M ,要求時間複雜度為O(N).
分析程式碼
- 最普通的解法是從左到右遍歷source 的每個字元,然後看如果以當前字元作為第一個字元出發是否匹配出match。時間複雜度較高O(N * M)。
- 本文KMP解法能夠做到時間複雜度O(N)
- 主要是生成match字串的nextArr 陣列,這個陣列的長度與match字串的長度一樣,nextArr[i]的含義是在match[i]之前的字串match[0…i-1] 中,必須以match[i-1]結尾的字尾子串(不能含有match[0])與必須以match[0]開頭的字首子串(不能含有match[i - 1])最大的匹配長度是多少。這個長度是nextArr[i]的值。
程式碼
// kmp
public int[] getNextArray(char[] ms){
if(ms.length == 1){
return new int[]{-1} ;
}
int[] next = new int[ms.length];
next[0] = -1;
next[1] = 0;
int pos = 2;
int cn = 0;
while(pos < next.length){
if(ms[pos - 1] == ms[cn]){
next[pos++] == ++cn;
}else if(cn > 0){
cn = next[cn];
}else{
next[pos++] = 0;
}
}
return next;
}
pubulic int kmp(String source, String match) {
int i = 0, j = 0;
char[] src = source.toCharArray();
char[] mat = match.toCharArray();
int sLen = src.length;
int mLen = mat.length;
int[] next = getNextArray(mat);
while(i < sLen && j < mLen){
//如果j = -1 ,或者當前字元匹配成功(src[i] = mat[j]), 都讓i++,j++
if(j == -1 || src[i] == mat[j]){
i++;
j++;
}else{
//如果j!= -1 且當前字元匹配失敗,則令i 不變, j = next[j] ,即讓match 串 右移 j- next[j] 個單位
j = next[j]; //此處體現next 陣列的作用, source 陣列無需退回。
}
}
if(j == mLen)
return i - j;
return -1;
}