1#[allow(clippy::many_single_char_names)]
19pub fn z_algorithm<T>(a: &[T]) -> Vec<usize>
20where
21 T: PartialEq + std::fmt::Debug,
22{
23 let n = a.len();
24 let mut z = vec![0; n];
25 let mut i = 0;
26 for j in 1..n {
27 if j + z[j - i] < i + z[i] {
28 debug_assert_eq!(a[j..(j + z[j - i])], a[..z[j - i]]);
29 z[j] = z[j - i];
30 } else {
31 let start = j + (i + z[i]).saturating_sub(j);
32 debug_assert_eq!(a[j..start], a[..(start - j)]);
33 let end = (start..n).find(|&k| a[k - j] != a[k]).unwrap_or(n);
34 debug_assert_eq!(a[j..end], a[..(end - j)]);
35 z[j] = end - j;
36 i = j;
37 }
38 }
39 z[0] = n;
40 z
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46 use rand::prelude::*;
47 #[test]
48 fn test() {
49 let chars = ['a', 'b', 'x', 'y'];
50 let mut rng = thread_rng();
51 for _ in 0..100 {
52 let n = rng.gen_range(1, 100);
53 let s = (0..n)
54 .map(|_| *chars.choose(&mut rng).unwrap())
55 .collect::<Vec<_>>();
56 let z = z_algorithm(&s);
57 for i in 0..n {
58 assert_eq!(z[i], lcp(&s, &s[i..]));
59 }
60 }
61 }
62
63 fn lcp(a: &[char], b: &[char]) -> usize {
64 let mut i = 0;
65 while i < a.len() && i < b.len() {
66 if a[i] != b[i] {
67 break;
68 }
69 i += 1;
70 }
71 i
72 }
73}