#![allow(dead_code)]
pub fn build_lcp(s: &[u8], sa: &[usize]) -> Vec<usize> {
let n = s.len();
if n == 0 {
return Vec::new();
}
let mut rank = vec![0usize; n];
for (i, &suf) in sa.iter().enumerate() {
rank[suf] = i;
}
let mut lcp = vec![0usize; n];
let mut h = 0usize;
for i in 0..n {
if rank[i] > 0 {
let j = sa[rank[i] - 1];
while i + h < n && j + h < n && s[i + h] == s[j + h] {
h += 1;
}
lcp[rank[i]] = h;
h = h.saturating_sub(1);
}
}
lcp
}
pub fn lcp_max_val(lcp: &[usize]) -> usize {
lcp.iter().copied().max().unwrap_or(0)
}
pub fn lcp_avg(lcp: &[usize]) -> f32 {
if lcp.is_empty() {
return 0.0;
}
lcp.iter().sum::<usize>() as f32 / lcp.len() as f32
}
pub fn distinct_substrings(n: usize, lcp: &[usize]) -> usize {
let total = n * (n + 1) / 2;
let sum_lcp: usize = lcp.iter().sum();
total.saturating_sub(sum_lcp)
}
pub fn lcp_query(lcp: &[usize], i: usize, j: usize) -> usize {
if i == j {
return usize::MAX;
}
let lo = i.min(j) + 1;
let hi = i.max(j);
if lo > hi || hi >= lcp.len() {
return 0;
}
lcp[lo..=hi].iter().copied().min().unwrap_or(0)
}
pub fn lcp_valid(lcp: &[usize], sa: &[usize]) -> bool {
lcp.len() == sa.len()
}
#[cfg(test)]
mod tests {
use super::*;
fn naive_sa(s: &[u8]) -> Vec<usize> {
let n = s.len();
let mut sa: Vec<usize> = (0..n).collect();
sa.sort_by_key(|&i| &s[i..]);
sa
}
#[test]
fn test_basic_lcp() {
let s = b"banana";
let sa = naive_sa(s);
let lcp = build_lcp(s, &sa);
assert_eq!(lcp[0], 0);
assert_eq!(lcp.len(), s.len());
}
#[test]
fn test_lcp_max() {
let s = b"aaaa";
let sa = naive_sa(s);
let lcp = build_lcp(s, &sa);
assert_eq!(lcp_max_val(&lcp), 3);
}
#[test]
fn test_lcp_all_distinct() {
let s = b"abcd";
let sa = naive_sa(s);
let lcp = build_lcp(s, &sa);
assert_eq!(lcp_max_val(&lcp), 0);
}
#[test]
fn test_distinct_substrings() {
let s = b"aa";
let sa = naive_sa(s);
let lcp = build_lcp(s, &sa);
let d = distinct_substrings(s.len(), &lcp);
assert_eq!(d, 2);
}
#[test]
fn test_lcp_valid() {
let s = b"hello";
let sa = naive_sa(s);
let lcp = build_lcp(s, &sa);
assert!(lcp_valid(&lcp, &sa));
}
#[test]
fn test_lcp_avg_nonnegative() {
let s = b"abcabc";
let sa = naive_sa(s);
let lcp = build_lcp(s, &sa);
assert!(lcp_avg(&lcp) >= 0.0);
}
#[test]
fn test_lcp_query_same_index() {
let s = b"abc";
let sa = naive_sa(s);
let lcp = build_lcp(s, &sa);
assert_eq!(lcp_query(&lcp, 1, 1), usize::MAX);
}
#[test]
fn test_empty_string() {
let lcp = build_lcp(b"", &[]);
assert!(lcp.is_empty());
}
#[test]
fn test_single_char() {
let s = b"a";
let sa = naive_sa(s);
let lcp = build_lcp(s, &sa);
assert_eq!(lcp.len(), 1);
assert_eq!(lcp[0], 0);
}
}