use suffix::SuffixTable;
pub fn longest_common_substring<T: AsRef<str>>(strs: &[T]) -> String {
let number_of_strings = strs.len();
let mut boundaries = Vec::new();
let mut concatenated = String::new();
for s in strs.iter() {
concatenated.push_str(s.as_ref());
boundaries.push(concatenated.len());
}
let sa = SuffixTable::new(&concatenated);
let pos = sa.table();
let lcp = sa.lcp_lens();
let mut lcs_len = 0u32;
let mut lcs_pos: u32 = 0;
'outer: for (win_p, win_l) in pos
.windows(number_of_strings)
.zip(lcp.windows(number_of_strings))
{
let mut included = vec![false; number_of_strings];
for &p in win_p {
let n = string_number(p, &boundaries);
if included[n] {
continue 'outer;
} else {
included[n] = true;
}
}
let m = win_l.iter().skip(1).min().unwrap(); let this_cs_len = *m;
let this_cs_pos = win_p[0];
if *m > lcs_len {
lcs_len = this_cs_len;
lcs_pos = this_cs_pos;
}
}
let lcs_len = lcs_len as usize;
let lcs_pos = lcs_pos as usize;
std::str::from_utf8(&concatenated.as_bytes()[lcs_pos..lcs_pos + lcs_len])
.unwrap()
.to_owned()
}
pub fn common_substrings<T: AsRef<str>>(strs: &[T]) -> Vec<String> {
let number_of_strings = strs.len();
let mut boundaries = Vec::new();
let mut concatenated = String::new();
for s in strs.iter() {
concatenated.push_str(s.as_ref());
boundaries.push(concatenated.len());
}
let sa = SuffixTable::new(&concatenated);
let pos = sa.table();
let lcp = sa.lcp_lens();
let mut css = Vec::new();
'outer: for (win_p, win_l) in pos
.windows(number_of_strings)
.zip(lcp.windows(number_of_strings))
{
let mut included = vec![false; number_of_strings];
for &p in win_p {
let n = string_number(p, &boundaries);
if included[n] {
continue 'outer;
} else {
included[n] = true;
}
}
let m = win_l.iter().skip(1).min().unwrap(); let this_cs_len = *m as usize;
let this_cs_pos = win_p[0] as usize;
let this_cs =
std::str::from_utf8(&concatenated.as_bytes()[this_cs_pos..this_cs_pos + this_cs_len])
.unwrap()
.to_owned();
css.push(this_cs);
}
css
}
fn string_number(position: u32, boundaries: &[usize]) -> usize {
match boundaries.binary_search(&(position as usize)) {
Ok(idx) => idx + 1,
Err(idx) => idx,
}
}