一、Sunday算法思想
備註:因爲Sunday理解起來比較簡單,就直接用參考的文章內容了。鏈接:https://www.cnblogs.com/sunsky303/p/11693792.html
Sunday算法是從前往後匹配,在匹配失敗時關注的是主串中參加匹配的最末位字符的下一位字符。
如果該字符沒有在模式串中出現則直接跳過,即移動位數 = 模式串長度 + 1;
否則,其移動位數 = 模式串長度 - 該字符最右出現的位置(以0開始) = 模式串中該字符最右出現的位置到尾部的距離 + 1。
二、需要注意的問題
1、如果父串中對應子串末尾下一個位置的字符在子串中存在,且不止一個要怎麼處理
方法:爲了不遺漏可能的匹配,應該是跳到使得子串中最右一個字符與父串中的該字符對應,這樣跳過的距離最小,且是安全的。
2、可能會出現最後一次移動後father剩餘長度與son長度不一致的情況
方法:做循環時,while條件判斷中加上子串移動的位置,如下代碼
while (i <= fatherLength - sonLength + j)
三、Java代碼實現
public class Sunday {
/**
* 判斷子串中是否存在末尾下一個位置對應的父串的字符
* 每次從後往前匹配,爲了不遺漏可能的匹配,應該是跳到使得子串中最右一個字符與父串中的該字符對應,
* 這樣跳過的距離最小,且是安全的。
*/
public static int contains(char[] sonArray, char ch) {
for (int i = sonArray.length - 1; i >= 0; i--) {
if (sonArray[i] == ch) {
return i;
}
}
return -1;
}
public static int search(String father, String son) {
//這裏轉爲char數組要更方便些
char[] fatherArray = father.toCharArray();
char[] sonArray = son.toCharArray();
int fatherLength = fatherArray.length;
int sonLength = sonArray.length;
int i = 0, j = 0;
//+ j是可能會出現最後一次移動father剩餘長度與son長度不一致的情況
while (i <= fatherLength - sonLength + j) {
if (fatherArray[i] != sonArray[j]) {
//如果父串與子串當前字符不相等
if (i == fatherLength - sonLength + j) {
//這裏說明子串已經是在和父串中最後可能想等的字符比較過了,並且後面也沒有可比較的了,所以返回
return -1;
}
//如果父串的中間部分與子串匹配,且結果不相等
//就從子串最後面開始,找出子串最後一位的下一位對應父串的字符在子串中是否存在
int pos = contains(sonArray, fatherArray[i - j + sonLength]);
if (pos == -1) {
//不存在則直接跳到再下一位,子串從頭開始
i = i - j + sonLength + 1;
j = 0;
} else {
//存在則將這個字符與子串最右邊與它相同的字符對其,並再次從頭開始比較
i = i + sonLength - pos - j;
j = 0;
}
} else {
//如果父串與子串當前字符相等
if (j == sonLength - 1) {
//如果比較到了子串的最後一位,說明已經存在
return i - j;
} else {
//不是子串最後一位,則進行下一個字符的對比
i++;
j++;
}
}
}
return -1;
}
public static void main(String[] args) {
String father = "ABABEABABABABCBA";
String son = "ABABC";
System.out.println(search(father, son));
}
}