#include <iostream>
#include <string>
using namespace std;
void makeBC(int* bc,string pat) {
for(int i = 0; i <= 255; i++)
bc[i] = -1;
for(int i = 0; i < pat.length(); i++)
bc[pat[i]] = i;
}
void makeF(int* f,int* s,string pat) {
int m = pat.length();
for(int k = 0; k <= m; k++)
s[k] = 0;
int i = m, j = m+1;
f[i] = j;
while(i > 0) {
while(j <= m && pat[i-1] != pat[j-1]) {
if(s[j] == 0)
s[j] = j-i;
j = f[j];
}
i--;
j--;
f[i] = j;
}
}
void makeS(int* f,int* s,string pat) {
int m = pat.length();
int j = f[0];
for(int i = 0; i <= m; i++) {
if(s[i] == 0)
s[i] = j;
if(i == j)
j = f[j];
}
}
void BM(string text, string pat) {
int m = pat.length();
int n = text.length();
int bc[256]; //array bad character
int f[m+1]; //F function preprocess contained the starting
//position of the widest border of the suffix
//of the pattern beginning at position i.
int s[m+1]; //Mảng s này người ta nói là lưu khoảng cách dịch chuyển
//lớn nhất có thể.
//make preprocess
makeBC(bc,pat);
makeF(f,s,pat);
makeS(f,s,pat);
//search
int i = 0,j;
while(i <= m-n) {
j = m-1;
while(j >= 0 && pat[j] == text[i+j])
j--;
if(j < 0) {
cout << "Found pattern at index: " << i << endl;
i += s[0];
}
else
i += std::max(s[j+1], j - bc[text[i+j]]);
}
}
int main() {
string text = "abcababacbabbababcbcab";
string pat = "abbabab";
BM(text,pat);
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8c3RyaW5nPgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKdm9pZCBtYWtlQkMoaW50KiBiYyxzdHJpbmcgcGF0KQkJewoJCglmb3IoaW50IGkgPSAwOyBpIDw9IDI1NTsgaSsrKQoJCWJjW2ldID0gLTE7CgkJCglmb3IoaW50IGkgPSAwOyBpIDwgcGF0Lmxlbmd0aCgpOyBpKyspCQoJCWJjW3BhdFtpXV0gPSBpOwp9Cgp2b2lkIG1ha2VGKGludCogZixpbnQqIHMsc3RyaW5nIHBhdCkJewoJCglpbnQgbSA9IHBhdC5sZW5ndGgoKTsKCWZvcihpbnQgayA9IDA7IGsgPD0gbTsgaysrKQkKCQlzW2tdID0gMDsKCQoJaW50IGkgPSBtLCBqID0gbSsxOwoJZltpXSA9IGo7CgkKCXdoaWxlKGkgPiAwKQl7CgkJCgkJd2hpbGUoaiA8PSBtICYmIHBhdFtpLTFdICE9IHBhdFtqLTFdKQl7CgkJCQoJCQlpZihzW2pdID09IDApCgkJCQlzW2pdID0gai1pOwoJCQlqID0gZltqXTsKCQl9CgkJaS0tOwoJCWotLTsKCQlmW2ldID0gajsKCX0KCQoJCn0KCnZvaWQgbWFrZVMoaW50KiBmLGludCogcyxzdHJpbmcgcGF0KQl7CgkKCWludCBtID0gcGF0Lmxlbmd0aCgpOwoJaW50IGogPSBmWzBdOwoJCglmb3IoaW50IGkgPSAwOyBpIDw9IG07IGkrKykJewoJCQoJCWlmKHNbaV0gPT0gMCkKCQkJCXNbaV0gPSBqOwoJCQkKCQlpZihpID09IGopCgkJCQlqID0gZltqXTsKCX0KCQoJCn0KCnZvaWQgQk0oc3RyaW5nIHRleHQsIHN0cmluZyBwYXQpCXsKCQoJaW50IG0gPSBwYXQubGVuZ3RoKCk7CglpbnQgbiA9IHRleHQubGVuZ3RoKCk7CglpbnQgYmNbMjU2XTsgLy9hcnJheSBiYWQgY2hhcmFjdGVyCglpbnQgZlttKzFdOyAvL0YgZnVuY3Rpb24gcHJlcHJvY2VzcyBjb250YWluZWQgdGhlIHN0YXJ0aW5nIAoJCQkJLy9wb3NpdGlvbiBvZiB0aGUgd2lkZXN0IGJvcmRlciBvZiB0aGUgc3VmZml4IAoJCQkJLy9vZiB0aGUgcGF0dGVybiBiZWdpbm5pbmcgYXQgcG9zaXRpb24gaS4KCWludCBzW20rMV07IC8vTeG6o25nIHMgbsOgeSBuZ8aw4budaSB0YSBuw7NpIGzDoCBsxrB1IGtob+G6o25nIGPDoWNoIGThu4tjaCBjaHV54buDbgoJCQkJLy9s4bubbiBuaOG6pXQgY8OzIHRo4buDLgoJCgkvL21ha2UgcHJlcHJvY2VzcwoJbWFrZUJDKGJjLHBhdCk7CgltYWtlRihmLHMscGF0KTsKCW1ha2VTKGYscyxwYXQpOwoJCgkvL3NlYXJjaAoJaW50IGkgPSAwLGo7CgkKCXdoaWxlKGkgPD0gbS1uKQl7CgkJCgkJaiA9IG0tMTsKCQl3aGlsZShqID49IDAgJiYgcGF0W2pdID09IHRleHRbaStqXSkKCQkJai0tOwoJCQkKCQlpZihqIDwgMCkJewoJCQkKCQkJY291dCA8PCAiRm91bmQgcGF0dGVybiBhdCBpbmRleDogIiA8PCBpIDw8IGVuZGw7CgkJCWkgKz0gc1swXTsKCQl9CgkJZWxzZQoJCQlpICs9IHN0ZDo6bWF4KHNbaisxXSwgaiAtIGJjW3RleHRbaStqXV0pOwoJfQoJCn0KCmludCBtYWluKCkJewoKCXN0cmluZyB0ZXh0ID0gImFiY2FiYWJhY2JhYmJhYmFiY2JjYWIiOwoJc3RyaW5nIHBhdCA9ICJhYmJhYmFiIjsKCglCTSh0ZXh0LHBhdCk7CglyZXR1cm4gMDsKfQ==