一、Sunday 匹配机制
匹配机制非常容易理解:
目标字符串 haystack,长度为len
模式串 needle,长度为len_pattern
当前查询索引 idx (初始为 0)
待匹配字符串 search= haystack.substring(idx, idx + len_pattern),即从idx下标开始取长度len_pattern的字符串;
每次匹配都会从目标字符串中提取待匹配字符串与模式串进行匹配:
若匹配,则返回当前 idx
不匹配,则查看待匹配字符串的后一位字符 c:
若c存在于模式串 needle中,则 idx = idx + 偏移表[c]
否则,idx = idx + len(needle)
Repeat Loop 直到 idx + len(needle) > len(haystack)
二、偏移表
偏移表的作用是存储每一个在 模式串 中出现的字符,在 模式串 中出现的最右位置到尾部的距离 +1+1
三、举例
String: checkthisout
Pattern: this
Step 1:
idx = 0
待匹配字符串为:chec
因为 chec != this
所以查看 chec 的下一个字符 k
k 不在 Pattern 里
所以查看 偏移表,idx = idx + 5
Step 2:
idx = 5
待匹配字符串为:this
因为 this == this
匹配,所以返回 5
四、算法分析
最坏情况:O(nm)
平均情况:O(n)
代码:
public static int sunday(String haystack, String needle) {
// 几种特殊情况,快速剪枝
if (haystack.equals(needle) || needle.isEmpty()) return 0;
if (needle.length() > haystack.length()) return -1;
int idx = 0;
int len_pattern = needle.length();
int len_search = haystack.length();
int len = len_search;
while (len_search >= len_pattern && idx + len_pattern <= len) {
String sub = haystack.substring(idx, idx + len_pattern);
if (sub.equals(needle)) return idx;
else {
int pos = getPos(haystack.charAt(idx + len_pattern == len ? idx + len_pattern - 1 : idx + len_pattern), needle.toCharArray());
if (pos == -1) {
idx += len_pattern + 1;
} else {
// 找到字符
idx += len_pattern - pos;
}
len_search = len - idx;
}
}
return -1;
}
public static int getPos(char ch, char[] tmp) {
for (int i = tmp.length - 1; i >= 0; i--) {
if (tmp[i] == ch) return i;
}
return -1;
}