Sunday算法
2017-08-30
Sunday算法是Daniel M.Sunday于1990年提出的字符串模式匹配。并不知道他是谁(来自百度)
Q:那么Sunday是干什么的?
s:吾看他能在期望O(n)的时间里知道在串S1中S2出现了几次x
Q:那他是怎么实现的呢?
s:就是在字符串发生失配的时候,跳过了尽可能多的字符,而且保证不错过某些可能的情况poi
s:那我举一个例子
S1串是 wypxs_a_b_e_rfliflisabersakeLLpoix
S2串是 saber
现在上面用i表示匹配到S1的第i个字符,j表示匹配到S2的第j个字符
显然在S1中只有一个S2。
那么Sunday怎么匹配的?
wypxs_a_b_e_rfliflisabersakeLLpoix
w | y | p | x | s | _ | a | _ | b | _ | e | _ | r | f | l | i | f | l | i | s | a | b | e | r | s | a | k | e | L | L | p | o | i | x |
s | a | b | e | r |
这是一开始的样子,发现第一个不一样。按照Sunday,就去S1的下一位找S2的字符.
S1中的下一个是'_'发现在S2中没有,就移动len(S2)+1;变成
w | y | p | x | s | _ | a | _ | b | _ | e | _ | r | f | l | i | f | l | i | s | a | b | e | r | s | a | k | e | L | L | p | o | i | x |
s | a | b | e | r |
这样还是刚才的操作,发现第一个还是不匹配,依旧移动len(S2)+1
w | y | p | x | s | _ | a | _ | b | _ | e | _ | r | f | l | i | f | l | i | s | a | b | e | r | s | a | k | e | L | L | p | o | i | x |
s | a | b | e | r |
然后.....这个有点长啊.......
w | y | p | x | s | _ | a | _ | b | _ | e | _ | r | f | l | i | f | l | i | s | a | b | e | r | s | a | k | e | L | L | p | o | i | x |
s | a | b | e | r |
现在还是不匹配?关键来了!发现不匹配了。现在看到了S1下一位是r,在S2中也有r,那这样吧r对其
w | y | p | x | s | _ | a | _ | b | _ | e | _ | r | f | l | i | f | l | i | s | a | b | e | r | s | a | k | e | L | L | p | o | i | x |
s | a | b | e | r |
现在竟然匹配了!然后ans++;可以继续跳了,找到下一个s,对齐
w | y | p | x | s | _ | a | _ | b | _ | e | _ | r | f | l | i | f | l | i | s | a | b | e | r | s | a | k | e | L | L | p | o | i | x |
s | a | b | e | r |
到‘k’不匹配没有,看到下一位L跳6个,发现没了。结束ans最后的
这样就可以保证跳到的都是可能会合法的情况,而且距离尽可能大.....poi
每一次贪心选最后一个字符出现的位置即如果S2是’ssaber‘碰到‘s’只跳到第二个‘s’的位置而不是第一个poi
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #define next saber using namespace std; char a[10000000+99999],b[5000+99]; int len1,len2,ans; int next[30]; bool pd(int i){ for(int j=0;j<len2;j++) if(a[i+j]!=b[j]){return 1;} return 0; } int main(){ cin>>a;cin>>b; len1=strlen(a),len2=strlen(b); for(int i=0;i<=26;i++)next[i]=len2+1; for(int i=0;i<len2;i++)next[b[i]-'a']=len2-i; for(int i=len1;i<=len1+99;i++)a[i]='z'+1; next['z'+1-'a']=len2+1; int i=0; while(i<len1){ if(pd(i))i+=next[a[i+len2]-'a']; else ans++,cout<<i+1<<" ",i+=next[a[i+len2]-'a']; } cout<<endl; cout<<ans; return 0; }
by:s_a_b_e_r