Skip to content

Commit 6bde4c3

Browse files
authored
Suffix array (#57)
* saving progress * update * add another lcp test * add another test * add another test, but it has a bug * actually do it this way * adding progress * now clippy passes * format * add another test * saving progress * clean * add another function + test * simplify * add docs * add some docs * finish docs * finish docs * Update suf_ary_find_many_strs_aizu.rs * add complexity * add back test * fix * test untested branch * test another path * add another assert * fix * test final branch * more asserts * simplify * asdf * hopefully this fixes CI * fix * another rename * less general; simpler code * update * fix test * fix one test * fix last test * golf * some updates * finish example * add another test * lint * consistent style --------- Co-authored-by: Luke Videckis <lukevideckis@gmail.com>
1 parent 708e6a1 commit 6bde4c3

15 files changed

+458
-1
lines changed

.github/workflows/code_cov.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
set -eo pipefail
55

66
executables=$(find target/debug/examples/ -type f -executable | sed 's/^/--object /')
7-
cov_flags=(-Xdemangler=rustfilt --ignore-filename-regex='/.cargo/registry' --instr-profile=ptc_rust.profdata "${executables}")
7+
cov_flags=(-Xdemangler=rustfilt --ignore-filename-regex='/.cargo/registry' --ignore-filename-regex='/rustc' --instr-profile=ptc_rust.profdata "${executables}")
88

99
cargo profdata -- merge -sparse default_*.profraw -o ptc_rust.profdata
1010
# shellcheck disable=SC2068 # double quotes cause command to fail, not sure why

Cargo.toml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ edition = "2024"
99

1010
[dependencies]
1111
proconio = "0.4.5"
12+
ac-library-rs = "0.1.1"
1213

1314
[[example]]
1415
name = "binary_trie"
@@ -134,6 +135,38 @@ path = "examples/graphs/hld_jump_on_tree_nodes.rs"
134135
name = "hld_jump_on_tree_edges"
135136
path = "examples/graphs/hld_jump_on_tree_edges.rs"
136137

138+
[[example]]
139+
name = "lcp_query_yosupo_zfunc"
140+
path = "examples/strings/lcp_query_yosupo_zfunc.rs"
141+
142+
[[example]]
143+
name = "lcp_query_yosupo_palindrome"
144+
path = "examples/strings/lcp_query_yosupo_palindrome.rs"
145+
146+
[[example]]
147+
name = "suf_ary_cmp_aizu"
148+
path = "examples/strings/suf_ary_cmp_aizu.rs"
149+
150+
[[example]]
151+
name = "suf_ary_find_str_aizu"
152+
path = "examples/strings/suf_ary_find_str_aizu.rs"
153+
154+
[[example]]
155+
name = "suf_ary_find_many_strs_aizu"
156+
path = "examples/strings/suf_ary_find_many_strs_aizu.rs"
157+
158+
[[example]]
159+
name = "suf_ary_find_substr_aizu"
160+
path = "examples/strings/suf_ary_find_substr_aizu.rs"
161+
162+
[[example]]
163+
name = "suf_ary_find_substr_many_aizu"
164+
path = "examples/strings/suf_ary_find_substr_many_aizu.rs"
165+
166+
[[example]]
167+
name = "compress"
168+
path = "examples/helpers/compress.rs"
169+
137170
[[example]]
138171
name = "cuts_yosupo"
139172
path = "examples/graphs/cuts_yosupo.rs"

examples/helpers/compress.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// verification-helper: PROBLEM https://onlinejudge.u-aizu.ac.jp/courses/lesson/8/ITP2/all/ITP2_5_A
2+
3+
use proconio::input;
4+
use programming_team_code_rust::helpers::compress::compress;
5+
use programming_team_code_rust::strings::suf_ary::SufAry;
6+
7+
fn main() {
8+
input! {
9+
n: usize,
10+
a: [i32; 2 * n]
11+
}
12+
13+
let (compressed, max_val) = compress::<i32>(&a);
14+
15+
let suf_ary = SufAry::new(&compressed, max_val);
16+
17+
let mut indexes = (0..n).collect::<Vec<usize>>();
18+
19+
indexes.sort_by(|&i1, &i2| suf_ary.cmp_substrs(2 * i1..2 * i1 + 2, 2 * i2..2 * i2 + 2));
20+
21+
for i in indexes {
22+
println!("{} {}", a[2 * i], a[2 * i + 1]);
23+
}
24+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// verification-helper: PROBLEM https://judge.yosupo.jp/problem/enumerate_palindromes
2+
3+
use proconio::input;
4+
use programming_team_code_rust::strings::suf_ary::SufAry;
5+
6+
fn main() {
7+
input! {
8+
s: String
9+
}
10+
11+
let mut s_vec = s.chars().map(|c| c as usize).collect::<Vec<usize>>();
12+
let n = s_vec.len();
13+
let s_rev = s_vec.clone().into_iter().rev();
14+
15+
s_vec.push(0);
16+
s_vec.extend(s_rev);
17+
18+
let suf_ary = SufAry::new(&s_vec, 255);
19+
20+
for i in 0..n {
21+
for j in i..std::cmp::min(i + 2, n) {
22+
print!(
23+
"{} ",
24+
suf_ary.len_lcp(j, (n - i - 1) + n + 1) * 2 - (i == j) as usize
25+
);
26+
}
27+
}
28+
29+
println!();
30+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// verification-helper: PROBLEM https://judge.yosupo.jp/problem/zalgorithm
2+
3+
use proconio::input;
4+
use programming_team_code_rust::strings::suf_ary::SufAry;
5+
6+
fn main() {
7+
input! {
8+
s: String
9+
}
10+
11+
let s_vec = s.chars().map(|c| c as usize).collect::<Vec<usize>>();
12+
13+
let suf_ary = SufAry::new(&s_vec, 255);
14+
15+
for i in 0..s_vec.len() {
16+
print!("{} ", suf_ary.len_lcp(0, i));
17+
}
18+
19+
println!();
20+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// verification-helper: PROBLEM https://onlinejudge.u-aizu.ac.jp/courses/lesson/8/ITP2/all/ITP2_3_D
2+
3+
use proconio::input;
4+
use programming_team_code_rust::helpers::compress::compress;
5+
use programming_team_code_rust::strings::suf_ary::SufAry;
6+
7+
fn main() {
8+
input! {
9+
n: usize,
10+
mut a: [i32; n],
11+
m: usize,
12+
b: [i32; m]
13+
}
14+
15+
let are_equal = a == b;
16+
17+
a.push(-1);
18+
a.extend(b);
19+
20+
let (cmps, max_val) = compress(&a);
21+
let suf_ary = SufAry::new(&cmps, max_val);
22+
let res = suf_ary.cmp_substrs(0..n, n + 1..n + 1 + m);
23+
24+
if are_equal {
25+
assert_eq!(res, std::cmp::Ordering::Equal);
26+
assert_eq!(suf_ary.cmp_sufs(0, n + 1), std::cmp::Ordering::Greater);
27+
println!("0");
28+
} else {
29+
assert_eq!(res, suf_ary.cmp_sufs(0, n + 1));
30+
println!("{}", (res == std::cmp::Ordering::Less) as usize);
31+
}
32+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// verification-helper: PROBLEM https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_14_D
2+
3+
use proconio::input;
4+
use programming_team_code_rust::strings::suf_ary::SufAry;
5+
6+
fn main() {
7+
input! {
8+
s: String,
9+
q: usize,
10+
}
11+
12+
let s_vec = s.chars().map(|x| x as usize).collect::<Vec<usize>>();
13+
let suf_ary = SufAry::new(&s_vec, 255);
14+
15+
for _ in 0..q {
16+
input! {
17+
t: String
18+
}
19+
let t_vec = t.chars().map(|x| x as usize).collect::<Vec<usize>>();
20+
let range = suf_ary.find_str(&t_vec);
21+
println!("{}", !range.is_empty() as usize);
22+
}
23+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// verification-helper: PROBLEM https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_14_B
2+
3+
use proconio::input;
4+
use programming_team_code_rust::strings::suf_ary::SufAry;
5+
6+
fn main() {
7+
input! {
8+
s: String,
9+
t: String
10+
}
11+
12+
let s_vec = s.chars().map(|x| x as usize).collect::<Vec<usize>>();
13+
let t_vec = t.chars().map(|x| x as usize).collect::<Vec<usize>>();
14+
15+
let suf_ary = SufAry::new(&s_vec, 255);
16+
let range = suf_ary.find_str(&t_vec);
17+
let mut res: Vec<usize> = Vec::new();
18+
res.extend_from_slice(&suf_ary.sa[range]);
19+
res.sort();
20+
21+
for val in res {
22+
println!("{}", val);
23+
}
24+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// verification-helper: PROBLEM https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_14_B
2+
3+
use proconio::input;
4+
use programming_team_code_rust::strings::suf_ary::SufAry;
5+
6+
fn main() {
7+
input! {
8+
s: String,
9+
t: String
10+
}
11+
12+
let m = t.chars().count();
13+
let mut both = t.chars().map(|x| x as usize).collect::<Vec<usize>>();
14+
both.extend(s.chars().map(|x| x as usize).collect::<Vec<usize>>());
15+
16+
let suf_ary = SufAry::new(&both, 255);
17+
let mut res = suf_ary.sa[suf_ary.find_substr(0..m)]
18+
.iter()
19+
.copied()
20+
.filter(|&i| i >= m)
21+
.map(|i| i - m)
22+
.collect::<Vec<usize>>();
23+
res.sort();
24+
25+
for val in res {
26+
println!("{}", val);
27+
}
28+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// verification-helper: PROBLEM https://onlinejudge.u-aizu.ac.jp/problems/ALDS1_14_D
2+
3+
use proconio::input;
4+
use programming_team_code_rust::data_structures::rmq::RMQ;
5+
use programming_team_code_rust::strings::suf_ary::SufAry;
6+
7+
fn main() {
8+
input! {
9+
s: String,
10+
q: usize
11+
}
12+
13+
let mut s = s.chars().map(|x| x as usize).collect::<Vec<usize>>();
14+
15+
let mut length = vec![s.len()];
16+
17+
for _ in 0..q {
18+
input! {
19+
t: String,
20+
}
21+
let t = t.chars().map(|x| x as usize).collect::<Vec<usize>>();
22+
s.extend(t);
23+
length.push(s.len());
24+
}
25+
26+
let suf_ary = SufAry::new(&s, 255);
27+
let rmq = RMQ::new(&suf_ary.sa, std::cmp::min);
28+
29+
for i in 0..q {
30+
let idx = rmq.query(suf_ary.find_substr(length[i]..length[i + 1]));
31+
println!(
32+
"{}",
33+
(idx + length[i + 1] - length[i] <= length[0]) as usize
34+
);
35+
}
36+
}

0 commit comments

Comments
 (0)