1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
//! KMP 法。
use super::super::traits::push_pop;
use std::fmt::Debug;
use std::ops::Range;
use push_pop::{PopBack, PushBack};
/// KMP 法 (Knuth–Morris–Pratt algorithm)。
///
/// 文字列 $S$ を入力とする。
/// 各 $S\[\\dots i\]$ ($0\\le i\\le |S|$) の最長 border と最長 tagged border
/// の長さを求める。該当する border が存在しない要素は $-1$ とする。
///
/// 文字列 $S\[\\dots i\]$ の _border_ とは、$S\[\\dots i\]$ の真部分文字列であり、$S\[\\dots i\]$
/// の接頭辞かつ接尾辞であるような文字列である。
///
/// 文字列 $S\[\\dots i\]$ の border $S\[\\dots j\]$ ($0\\le j < i$) が $S\[j\] \\neq S\[i\]$
/// を満たすとき、$S\[\\dots j\]$ は $S\[\\dots i\]$ の _tagged border_ (_strict border_,
/// _strong border_) であると言う。ただし、$S\[|S|\]$ は $S$ 中に含まれない文字として定義する。
///
/// ```text
/// 0 1 2 3 4 5 6 7 8 9 ...
/// +-------------------+-------+
/// S | a a b a c a a b a | c ... |
/// +-------------------+-------+
/// ```
///
/// この例において、$S\[\\dots 4\] = \\mathtt{aaba}$ は $S\[\\dots 9\] = \\mathtt{aabacaaba}$
/// の border だが tagged border ではない ($S\[4\] = S\[9\] = \\mathtt{c}$)。一方、
/// $S\[\\dots 2\] = \\mathtt{aa}$ は tagged border である
/// ($S\[2\] = \\mathtt{b} \\neq S\[9\] = \\mathtt{c}$)。
///
/// この tagged border を用いることで、パターン検索を高速に行う。
///
/// # Idea
/// tagged border を $O(|S|)$ 時間で求める方法と、パターン検索を $O(|T|)$
/// 時間で行う方法について書く。
///
/// # Implementation notes
/// パターンが静的な場合であれば最長 border を求める必要はない。
/// パターンの末尾に対する push のみを考慮する場合も同様のはず。
/// ここではパターンの末尾に対する pop を行える実装になっており、その更新の際には最長
/// border の長さが必要になるはず。
///
/// # Complexity
/// 構築は $O(|S|)$ 時間。パターン末尾における更新は $O(\\log(|S|))$ 時間。
/// ただし、末尾への追加はこれに worst $O(|S|)$ (amortized $O(1)$) 時間が加わる。
///
/// # References
/// - Knuth, D. E., Morris, Jr, J. H., & Pratt, V. R. (1977). Fast pattern matching in strings. _SIAM journal on computing, 6_(2), 323-350.
///
/// # See also
/// - <https://snuke.hatenablog.com/entry/2014/12/01/235807>
/// - <https://snuke.hatenablog.com/entry/2017/07/18/101026>
/// - <https://potetisensei.hatenablog.com/entry/2017/07/10/174908>
/// - <http://www-igm.univ-mlv.fr/~lecroq/string/node8.html>
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct KmpSearcher<T: Eq> {
pat: Vec<T>,
fail: Vec<usize>,
fail1: Vec<usize>,
}
impl<T: Eq> From<Vec<T>> for KmpSearcher<T> {
fn from(pat: Vec<T>) -> Self {
let len = pat.len();
let fail1 = vec![1_usize.wrapping_neg(); len + 1];
let fail = fail1.clone();
let mut self_ = Self { pat, fail1, fail };
for i in 0..self_.pat.len() {
let (f, f1) = self_.calc_fail(i);
self_.fail1[i + 1] = f1;
self_.fail[i + 1] = f;
}
self_
}
}
impl<T: Eq> KmpSearcher<T> {
fn calc_fail(&self, i: usize) -> (usize, usize) {
let pat_i = &self.pat[i];
let mut j = self.fail1[i];
while j < self.pat.len() && pat_i != &self.pat[j] {
j = self.fail[j];
}
j = j.wrapping_add(1);
match self.pat.get(i + 1) {
Some(pat_ni) if pat_ni == &self.pat[j] => (self.fail[j], j),
_ => (j, j),
}
}
pub fn occurrences<'a>(&'a self, s: &'a [T]) -> Occurrences<'a, T> {
Occurrences {
text_index: 0,
pat_index: 0,
kmp: &self,
text: s,
}
}
}
pub struct Occurrences<'a, T: Eq> {
text_index: usize,
pat_index: usize,
kmp: &'a KmpSearcher<T>,
text: &'a [T],
}
impl<T: Eq> Iterator for Occurrences<'_, T> {
type Item = Range<usize>;
fn next(&mut self) -> Option<Self::Item> {
let text = self.text;
let pat = &self.kmp.pat;
if pat.is_empty() {
return if self.text_index < text.len() {
let i = self.text_index;
self.text_index += 1;
Some(i..i)
} else {
None
};
}
let mut j = self.pat_index;
for (i, c) in text[self.text_index..].iter().enumerate() {
let i = i + self.text_index;
while j < pat.len() && &pat[j] != c {
j = self.kmp.fail[j];
}
j = j.wrapping_add(1);
if j == pat.len() {
let e = i + 1;
let res = e - pat.len()..e;
self.text_index = e;
self.pat_index = self.kmp.fail[j];
return Some(res);
}
}
self.text_index = text.len();
None
}
}
impl<T: Eq> PushBack for KmpSearcher<T> {
type Input = T;
fn push_back(&mut self, x: T) {
let len = self.pat.len();
if len > 0 {
let j = self.fail1[len];
if &self.pat[j] == &x {
let tmp = self.fail[j];
self.fail[len] = tmp;
}
}
self.pat.push(x);
let (f, f1) = self.calc_fail(len);
self.fail1.push(f1);
self.fail.push(f);
}
}
impl<T: Eq> PopBack for KmpSearcher<T> {
type Output = usize;
fn pop_back(&mut self) -> Option<usize> {
if self.pat.is_empty() {
None
} else {
self.pat.pop();
self.fail1.pop();
let res = self.fail.pop();
*self.fail.last_mut().unwrap() = *self.fail1.last().unwrap();
res
}
}
}