Skip to content

Commit 26e4392

Browse files
committed
Add subset of string.hpp
1 parent 6e34caa commit 26e4392

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ pub(crate) mod internal_scc;
1818
pub(crate) mod internal_type_traits;
1919

2020
pub use fenwicktree::FenwickTree;
21+
pub use string::{suffix_array, suffix_array_arbitrary, suffix_array_manual};

src/string.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,112 @@
1+
fn sa_naive(s: &[i32]) -> Vec<usize> {
2+
let n = s.len();
3+
let mut sa: Vec<usize> = (0..n).collect();
4+
sa.sort_by(|&(mut l), &(mut r)| {
5+
if l == r {
6+
return std::cmp::Ordering::Equal;
7+
}
8+
while l < n && r < n {
9+
if s[l] != s[r] {
10+
return s[l].cmp(&s[r]);
11+
}
12+
l += 1;
13+
r += 1;
14+
}
15+
if l == n {
16+
std::cmp::Ordering::Less
17+
} else {
18+
std::cmp::Ordering::Greater
19+
}
20+
});
21+
sa
22+
}
123

24+
fn sa_doubling(s: &[i32]) -> Vec<usize> {
25+
let n = s.len();
26+
let mut sa: Vec<usize> = (0..n).collect();
27+
let mut rnk: Vec<i32> = s.to_vec();
28+
let mut tmp = vec![0; n];
29+
let mut k = 1;
30+
while k < n {
31+
let cmp = |&x: &usize, &y: &usize| {
32+
if rnk[x] != rnk[y] {
33+
return rnk[x].cmp(&rnk[y]);
34+
}
35+
let rx = if x + k < n { rnk[x + k] } else { -1 };
36+
let ry = if y + k < n { rnk[y + k] } else { -1 };
37+
rx.cmp(&ry)
38+
};
39+
sa.sort_by(cmp);
40+
tmp[sa[0]] = 0;
41+
for i in 1..n {
42+
tmp[sa[i]] = tmp[sa[i - 1]]
43+
+ if cmp(&sa[i - 1], &sa[i]) == std::cmp::Ordering::Less {
44+
1
45+
} else {
46+
0
47+
};
48+
}
49+
std::mem::swap(&mut tmp, &mut rnk);
50+
k *= 2;
51+
}
52+
sa
53+
}
54+
55+
fn sa_is(s: &[i32], upper: i32) -> Vec<usize> {
56+
sa_doubling(s)
57+
}
58+
59+
pub fn suffix_array_manual(s: &[i32], upper: i32) -> Vec<usize> {
60+
assert!(upper >= 0);
61+
for &elem in s {
62+
assert!(0 <= elem && elem <= upper);
63+
}
64+
sa_is(s, upper)
65+
}
66+
67+
pub fn suffix_array_arbitrary<T: Ord>(s: &[T]) -> Vec<usize> {
68+
let n = s.len();
69+
let mut idx: Vec<usize> = (0..n).collect();
70+
idx.sort_by_key(|&i| &s[i]);
71+
let mut s2 = vec![0; n];
72+
let mut now = 0;
73+
for i in 0..n {
74+
if i > 0 && s[idx[i - 1]] != s[idx[i]] {
75+
now += 1;
76+
}
77+
s2[idx[i]] = now;
78+
}
79+
sa_is(&s2, now)
80+
}
81+
82+
pub fn suffix_array(s: impl IntoIterator<Item = char>) -> Vec<usize> {
83+
let mut s2: Vec<i32> = s.into_iter().map(|x| x as i32).collect();
84+
sa_is(&s2, 255)
85+
}
86+
87+
#[cfg(test)]
88+
mod tests {
89+
use super::*;
90+
91+
#[test]
92+
fn test_sa_0() {
93+
let array = vec![0, 1, 2, 3, 4];
94+
let sa = sa_doubling(&array);
95+
assert_eq!(sa, vec![0, 1, 2, 3, 4]);
96+
}
97+
98+
#[test]
99+
fn test_sa_1() {
100+
let str = "abracadabra";
101+
let array: Vec<i32> = str.bytes().map(|x| x as i32).collect();
102+
let sa = sa_doubling(&array);
103+
assert_eq!(sa, vec![10, 7, 0, 3, 5, 8, 1, 4, 6, 9, 2]);
104+
let sa_naive = sa_naive(&array);
105+
assert_eq!(sa_naive, sa);
106+
let sa_is = sa_is(&array, 10);
107+
assert_eq!(sa_is, sa);
108+
109+
let sa_str = suffix_array(str.chars());
110+
assert_eq!(sa_str, sa);
111+
}
112+
}

0 commit comments

Comments
 (0)