Skip to main content
Back to problems
#411
Hard Algorithms

Minimum unique word abbreviation

Array String Backtracking Bit Manipulation
40.5% acceptance
Mar 31, 2026
184
146

No description available.

Solution

Rust
Time O(n²)
Space O(1)
LeetCode
solution.rs
impl Solution {
  pub fn min_abbreviation(target: String, dictionary: Vec<String>) -> String {
    let t: Vec<u8> = target.bytes().collect();
    let n = t.len();

    // Only consider dictionary words of the same length
    // For each such word, compute a bitmask of positions where it differs from target
    let diff_masks: Vec<u32> = dictionary.iter()
      .filter(|w| w.len() == n)
      .map(|w| {
        let wb = w.as_bytes();
        (0..n).fold(0u32, |mask, i| {
          if wb[i] != t[i] { mask | (1 << i) } else { mask }
        })
      })
      .collect();

    // Compute abbreviation length for a given mask
    // 1-bit = keep letter, 0-bit = part of a number
    let abbr_len = |mask: u32| -> usize {
      let mut len = 0usize;
      let mut i = 0usize;
      while i < n {
        if mask & (1 << i) != 0 {
          len += 1;
          i += 1;
        } else {
          len += 1; // one number token for a run of zeros
          while i < n && mask & (1 << i) == 0 {
            i += 1;
          }
        }
      }
      len
    };

    // A mask is valid if for every diff_mask d, mask & d != 0
    let is_valid = |mask: u32| -> bool {
      diff_masks.iter().all(|&d| mask & d != 0)
    };

    // Build abbreviation string from mask
    let build_abbr = |mask: u32| -> String {
      let mut s = String::new();
      let mut i = 0usize;
      while i < n {
        if mask & (1 << i) != 0 {
          s.push(t[i] as char);
          i += 1;
        } else {
          let start = i;
          while i < n && mask & (1 << i) == 0 {
            i += 1;
          }
          s.push_str(&(i - start).to_string());
        }
      }
      s
    };

    // Find mask with minimum abbreviation length that is valid
    let mut best_mask = (1u32 << n) - 1; // all letters (worst case = full word)
    let mut best_len = n;

    for mask in 0u32..(1u32 << n) {
      let len = abbr_len(mask);
      if len < best_len && is_valid(mask) {
        best_len = len;
        best_mask = mask;
      } else if len == best_len && is_valid(mask) && best_mask == (1u32 << n) - 1 {
        best_mask = mask;
      }
    }

    build_abbr(best_mask)
  }
}