假设有种彩票,从每日00:00:00开始,一小时出来一个号(24小时出24个号 00:00:00~23:00:00,假设为 a~z);
彩民可以随意买5个号,只要在这一天出来的彩票序列中存在自己买的序列即中奖;
显然:
①最早的结果是在凌晨04:00:00出来的,此时,幸运的人都是一个样,不幸的人各有各的不幸;
②按照一种方式分,未中奖者可以分成:第1个号就没中 ;1中2没中;1,2中 3没中 这样5种情况的,这5种情况中又各自有各种不同的情况;
③未中奖者的希望都在未来,在未知的号;
④有些未中奖者,直到等到后一个号出来才可以确定是不是中奖,有些则在看到19(24-5=19)点的号的时候就已经确定不能中奖了;
当然,这样的彩票是有bug的,中奖概率与你的号有关。
说回Sunday算法,这个算法比经典的KMP算法年轻,1990年,相对也好理解。
想法就是,当前无论因何原因没中奖,即使只差那么一丁点,想要中奖,你也得依靠后面的号,为确保不遗漏,从之后的第一个新号就开始看,现在你把这个新的号纳入可能的范围,那么至少这个新号与你手中的某个号相同,否则无论你手中的号现在有百分之多少的相似度,纳入这个号之后,都必然无法完全匹配。
下面是代码,代码来源https://blog.csdn.net/q547550831/article/details/51860017
const int maxNum = 128;
int shift[maxNum];
int Sunday(const string& T, const string& P) {
int n = T.length();
int m = P.length();
// 默认值,移动m+1位 //默认新出的号在你手中根本不存在
for(int i = 0; i < maxNum; i++) {
shift[i] = m + 1;
}
// 模式串P中每个字母出现的最后的下标
// 所对应的主串参与匹配的最末位字符的下一位字符移动到该位,所需要的移动位数
for(int i = 0; i < m; i++) {
shift[P[i]] = m - i;//
}
// 模式串开始位置在主串的哪里
int s = 0;
// 模式串已经匹配到的位置
int j;
while(s <= n - m) {
j = 0;
while(T[s + j] == P[j]) {
j++;
// 匹配成功
if(j >= m) {
return s;
}
}
// 找到主串中当前跟模式串匹配的最末字符的下一个字符
// 在模式串中出现最后的位置
// 所需要从(模式串末尾+1)移动到该位置的步数
s += shift[T[s + m]];
}
return -1;
}