Skip to main content
Back to problems
#2030
Hard Algorithms

Smallest k length subsequence with occurrences of a letter

String Stack Greedy Monotonic Stack
39.7% acceptance
Mar 1, 2026
512
15
You are given a string s, an integer k, a letter letter, and an integer repetition. Return the lexicographically smallest subsequence of s of length k that has letter appear at least repetition times.

Solution

Rust
Time O(n²)
Space O(n)
LeetCode
solution.rs
impl Solution {
  pub fn smallest_subsequence(s: String, k: i32, letter: char, repetition: i32) -> String {
    let k = k as usize;
    let rep = repetition as usize;
    let letter = letter as u8;
    let s = s.as_bytes();
    let n = s.len();

    let total_letter = s.iter().filter(|&&c| c == letter).count();

    let mut stack: Vec<u8> = Vec::new();
    let mut letter_count = 0usize; // letters in stack
    let mut remaining_letter = total_letter; // letters in s[i..]

    for i in 0..n {
      let c = s[i];
      let remaining = n - i; // chars left including current

      // Pop from stack if: current is smaller, we still have enough chars, and letter constraint holds.
      while !stack.is_empty() {
        let top = *stack.last().unwrap();
        if top <= c { break; }
        let stack_len = stack.len();
        // After pop, need (k - (stack_len-1)) chars from remaining (including current).
        if remaining < k - (stack_len - 1) { break; }
        // Letter constraint after pop.
        let new_letter_count = if top == letter { letter_count - 1 } else { letter_count };
        if new_letter_count + remaining_letter < rep { break; }

        if top == letter { letter_count -= 1; }
        stack.pop();
      }

      if stack.len() < k {
        if c == letter {
          stack.push(c);
          letter_count += 1;
        } else {
          // Only push if remaining spots can still be filled with enough letters.
          // After this push: spots_remaining = k - stack.len() - 1
          // Available letters from s[i+1..] = remaining_letter (c != letter, unchanged).
          let spots_remaining = k - stack.len() - 1;
          if letter_count + remaining_letter.min(spots_remaining) >= rep {
            stack.push(c);
          }
        }
      }

      if c == letter {
        remaining_letter -= 1;
      }
    }

    String::from_utf8(stack[..k].to_vec()).unwrap()
  }
}