概述
提起字符串匹配可能更多人會想到KMP算法,該算法時間複雜度爲O(m+n),而且也是我們在學習數據結構過程中最早接觸到的比較好的算法。但KMP算法需要在模式字符串有關聯的情況下,也即模式字符串前後綴字符相似度較高的情況下匹配效率比較高。但是在實際應用場景中模式字符串更多情況下是無規律的,因此在工程應用中字符串匹配問題的解決更多的使用的是sunday算法。
解題思路
sunday算法較之於BM算法最大的不同點在於sunday算法在匹配的過程中主串中參加匹配的最末位字符的下一位字符。
- 如果末尾的下一位字符(如該字符爲'a')沒有在模式字符串中出現過,則直接跳到'a'的下一位字符開始新一輪的比較
- 如果模式字符串中包含'a',則將模式字符串中從左到右中最早出現的字符'a'與源字符串中的'a'對應開始新一輪的匹配
我們下邊舉一個例子來說明sunday算法的匹配過程。比如在一個主串"substring searching"中查找模式串"search"。
- 開始時,將模式字符串和主字符串左側對齊開始進行匹配
- 在匹配的過程中發現在第二個字符
e
處出現匹配失敗的情況。此時我們關注參與匹配的最末尾字符的下一位即i
,由於模式字符串中並沒有i
,因此模式字符串直接跳過一大片,向右移動位數=模式字符串長度+1,也即移動到字符n
的位置。
- 在新一輪的匹配過程中發現第一個字符便出現了不匹配的情況。然後我們看到參與匹配的末尾字符的下一位字符爲
r
,並且r
存在於模式字符串中因此可以將模式字符串移動3位(移動到模式字符串中的r
和主字符串中的r
對齊)如下:
- 在新一輪匹配過程中發現匹配成功,結束匹配返回匹配的位置。
代碼
class Solution {
//使用sunday算法來求解
public int strStr(String haystack, String needle) {
//邊界判斷
if(needle.equals("")||needle==null){
return 0;
}
if(haystack==null){
return -1;
}
char [] haystackArray=haystack.toCharArray();
char []needleArray=needle.toCharArray();
int haystackLength=haystackArray.length;
int needleLength=needleArray.length;
//定義偏移數組
int move[]=new int[256];
//對偏移數組進行初始化工作
for(int i=0;i<256;i++){
move[i]=needleLength+1;
}
for(int i=0;i<needleLength;i++){
move[needleArray[i]]=needleLength-i;
}
//模式字符串第一個字符在匹配過程與源字符串對應的未知,j表示當前已經匹配的字符個數
int s=0,j=0;
//進行匹配
while(s<=haystackLength-needleLength){
j=0;
while(haystackArray[s+j]==needleArray[j]){
j++;
if(j==needleLength){
return s;
}
}
if(s<haystackLength-needleLength){
s+=move[haystackArray[s+needleLength]];
}else{
return -1;
}
}
return -1;
}
}