Challenge 44

Smallest Window Containing All Characters

Given two strings, s and t, find the smallest substring of s that contains all the characters of t (including duplicates).

  • If no such substring exists, return None.
  • If there are multiple valid substrings, return the first one found.
  • The input strings may contain any printable ASCII characters.

You should aim for O(n) time complexity using an efficient approach.

Example:


pub fn smallest_window(s: &str, t: &str) -> Option<String> {
    // your implementation goes here
    // don't touch the code in the main function below
}

fn main() {
    // Test 1: "ADOBECODEBANC", "ABC" -> "BANC"
    let result1 = smallest_window("ADOBECODEBANC", "ABC");
    let expected1 = Some("BANC".to_string());
    if result1 != expected1 {
        panic!("Test 1 failed: Expected {:?}, got {:?}", expected1, result1);
    }
    println!("Test 1 passed: smallest_window(\"ADOBECODEBANC\", \"ABC\") = {:?}", result1);

    // Test 2: "a", "a" -> "a"
    let result2 = smallest_window("a", "a");
    let expected2 = Some("a".to_string());
    if result2 != expected2 {
        panic!("Test 2 failed: Expected {:?}, got {:?}", expected2, result2);
    }
    println!("Test 2 passed: smallest_window(\"a\", \"a\") = {:?}", result2);

    // Test 3: "a", "b" -> None
    let result3 = smallest_window("a", "b");
    let expected3 = None;
    if result3 != expected3 {
        panic!("Test 3 failed: Expected {:?}, got {:?}", expected3, result3);
    }
    println!("Test 3 passed: smallest_window(\"a\", \"b\") = {:?}", result3);

    // Test 4: "ab", "b" -> "b"
    let result4 = smallest_window("ab", "b");
    let expected4 = Some("b".to_string());
    if result4 != expected4 {
        panic!("Test 4 failed: Expected {:?}, got {:?}", expected4, result4);
    }
    println!("Test 4 passed: smallest_window(\"ab\", \"b\") = {:?}", result4);

    // Test 5: "abcdef", "xyz" -> None
    let result5 = smallest_window("abcdef", "xyz");
    let expected5 = None;
    if result5 != expected5 {
        panic!("Test 5 failed: Expected {:?}, got {:?}", expected5, result5);
    }
    println!("Test 5 passed: smallest_window(\"abcdef\", \"xyz\") = {:?}", result5);
}

Solution

Click to Show/Hide Solution
#![allow(unused)]

fn main() {
pub fn smallest_window(s: &str, t: &str) -> Option<String> {
    if s.is_empty() || t.is_empty() || s.len() < t.len() {
        return None;
    }

    // Count frequencies of characters in t
    let mut t_freq = std::collections::HashMap::new();
    for c in t.chars() {
        *t_freq.entry(c).or_insert(0) += 1;
    }

    let required = t_freq.len();
    let mut formed = 0;
    let mut window_freq = std::collections::HashMap::new();

    let mut min_len = usize::MAX;
    let mut min_window_start = 0;

    let mut left = 0;
    let mut right = 0;
    let chars: Vec<char> = s.chars().collect();

    while right < chars.len() {
        // Add character at right to window
        let c = chars[right];
        *window_freq.entry(c).or_insert(0) += 1;

        // Check if this character fulfills a requirement
        if t_freq.contains_key(&c) && window_freq[&c] == t_freq[&c] {
            formed += 1;
        }

        // Shrink the window from the left
        while left <= right && formed == required {
            let c = chars[left];
            let window_len = right - left + 1;
            if window_len < min_len {
                min_len = window_len;
                min_window_start = left;
            }

            *window_freq.get_mut(&c).unwrap() -= 1;
            if t_freq.contains_key(&c) && window_freq[&c] < t_freq[&c] {
                formed -= 1;
            }
            left += 1;
        }
        right += 1;
    }

    if min_len == usize::MAX {
        None
    } else {
        Some(chars[min_window_start..min_window_start + min_len].iter().collect())
    }
}
}