Sunday
Sunday是从前往后匹配的算法,在匹配失败时重点关注的是文本串中参加匹配的最末位字符的下一位字符。如果该字符没有在模式串中出现则直接跳过,移动位数为模式串长度 + 1,否则移动位数为模式串长度 - 该字符最右出现的下标。
Sunday算法巧妙的地方在于它发现匹配失败之后可以直接考察文本串中参加匹配的最末尾字符的下一个字符。
例如当文本串S = "bcaitsnaxzfinihao",P = "nihao"。
S[0]为b,P[0]为n,匹配失败。关注文本串中参加匹配的最末位字符的下一位字符s,该字符并没在模式串中出现,因此将模式串向右移动模式串长度 + 1,即5 + 1 = 6。
互动实验
Sunday:窗口后一位决定移动距离
访问权限PRO
PRO EXCLUSIVE探索不止于此
尊享 Pro 权益解锁完整互动实验、进阶解析与精选参考答案。
S[7]为a,P[1]为i,匹配失败。关注文本串中参加匹配的最末位字符的下一位字符i,该字符在模式串中最右出现下标为1,因此将模式串向右移动模式串长度 - 最右下标,即5 - 1 = 4。
S[10]为f,P[0]为n,匹配失败。关注文本串中参加匹配的最末位字符的下一位字符a,该字符在模式串中最右出现下标为3,因此将模式串向右移动模式串长度 - 最右下标,即5 - 3 = 2。
此时,模式串匹配成功。
Sunday
C
#include <stdio.h>
#include <string.h>
int sunday(const char *s, const char *p) {
int s_len = strlen(s);
int p_len = strlen(p);
int i = 0;
int j = 0;
int result = 0;
while (i < s_len && j < p_len) {
if (s[i] == p[j]) {
i++;
j++;
continue;
}
int idx = result + p_len;
if (idx >= s_len) {
return -1;
}
int k = p_len - 1;
while (k >= 0 && s[idx] != p[k]) {
k--;
}
i = result;
i += p_len - k;
result = i;
j = 0;
if (result + p_len > s_len) {
return -1;
}
}
return j == p_len ? result : -1;
}
int main(void) {
const char *s = "bcaitsnaxzfinihao";
const char *p = "nihao";
printf("%d\n", sunday(s, p));
return 0;
}返回第一个完整匹配的起点下标,未找到返回-1,空模式串返回0。C/C++以字节为单位,Java以UTF-16代码单元为单位,Python以字符为单位;本节示例使用ASCII字符。
知识测验
题目
Sunday失配后看的是哪个字符?
知识测验
题目
模式长度5,窗口后一位在模式中最右下标为3,移动几格?
动手练习
计算窗口后的移动距离
文本zzabacaba,模式aba。记录每轮的窗口起点、失配字符和窗口后一位;按最右出现下标计算移动距离,找出第一次完整匹配。