use std::cmp::min;
pub fn levenshtein(a: &str, b: &str) -> usize {
let a_chars: Vec<char> = a.chars().collect();
let b_chars: Vec<char> = b.chars().collect();
let mut prev: Vec<usize> = (0..=b_chars.len()).collect();
let mut curr = vec![0; b_chars.len() + 1];
for (i, ca) in a_chars.iter().enumerate() {
curr[0] = i + 1;
for (j, cb) in b_chars.iter().enumerate() {
let cost = if ca == cb { 0 } else { 1 };
curr[j + 1] = min(min(curr[j] + 1, prev[j + 1] + 1), prev[j] + cost);
}
std::mem::swap(&mut prev, &mut curr);
}
prev[b_chars.len()]
}
#[cfg(test)]
mod tests {
use super::levenshtein;
#[test]
fn identity_and_empty_cases() {
assert_eq!(levenshtein("", ""), 0);
assert_eq!(levenshtein("focus", "focus"), 0);
assert_eq!(levenshtein("", "focus"), 5);
assert_eq!(levenshtein("focus", ""), 5);
}
#[test]
fn single_edit_cases() {
assert_eq!(levenshtein("focs", "focus"), 1); assert_eq!(levenshtein("focus", "focs"), 1); assert_eq!(levenshtein("focus", "focuz"), 1); }
#[test]
fn known_examples() {
assert_eq!(levenshtein("kitten", "sitting"), 3);
assert_eq!(levenshtein("cargo", "focus"), 5);
}
#[test]
fn symmetric() {
let a = "preset";
let b = "present";
assert_eq!(levenshtein(a, b), levenshtein(b, a));
}
}