use crate::generate_vec_with;
const R: usize = 256;
pub struct KMP {
pat: String,
dfa: Vec<Vec<usize>>,
}
fn char_at(s: &str, d: usize) -> usize {
s.as_bytes()[d] as usize
}
impl KMP {
pub fn new(pat: String) -> Self {
let m = pat.len();
let mut dfa = generate_vec_with!(vec![0; m], R);
dfa[char_at(&pat, 0)][0] = 1;
let mut x = 0;
for j in 1..m {
(0..R).for_each(|c| {
dfa[c][j] = dfa[c][x];
});
let i = char_at(&pat, j);
dfa[i][j] = j + 1;
x = dfa[i][x];
}
KMP { pat, dfa }
}
pub fn search(&self, txt: &str) -> usize {
let n = txt.len();
let m = self.pat.len();
let mut j = 0;
let i: Vec<usize> = (0..n)
.filter(|&i| {
j = self.dfa[char_at(txt, i)][j];
j >= m
})
.take(1)
.collect();
if j == m {
if let Some(i) = i.first() {
i + 1 - m
} else {
n - m
}
} else {
n
}
}
}
#[cfg(test)]
mod test {
use super::KMP;
#[test]
fn test() {
let kmp = KMP::new("abc".to_string());
assert_eq!(kmp.search("ababac"), 6);
assert_eq!(kmp.search("ababcc"), 2);
assert_eq!(kmp.search("ababccababcc"), 2);
assert_eq!(kmp.search("abcbcc"), 0);
assert_eq!(kmp.search("babcbcc"), 1);
assert_eq!(kmp.search("aabcbcc"), 1);
assert_eq!(kmp.search("ab"), 2);
}
}