Knowledge Guide
HomeDSACompany Practice

hard Minimum Window Substring

Problem Statement

Given a string s and t of length m and n respectively, find the smallest substring in a given string 's' that contains all the characters (including duplicate) of another string 't'. The order of characters in 't' doesn't matter, but the substring in 's' must include all characters of 't', possibly with additional characters.

If no such substring exists, return an empty string.

Examples

Example 1:

Example 2:

Example 3:

Try it yourself

Try solving this question here:

✅ Solution Minimum Window Substring

Problem Statement

Given a string s and t of length m and n respectively, find the smallest substring in a given string 's' that contains all the characters (including duplicate) of another string 't'. The order of characters in 't' doesn't matter, but the substring in 's' must include all characters of 't', possibly with additional characters.

If no such substring exists, return an empty string.

Examples

Example 1:

  • Input: s = "xyyzyzyx", t = "xyz"
  • Expected Output: "zyx"
  • Justification: "zyx" is the shortest substring of 's' that contains 'x', 'y', and 'z'.

Example 2:

  • Input: s = "abracadabra", t = "aa"
  • Expected Output: "ada"
  • Justification: "ada" at the end of 's' is the shortest substring containing all 'a's in 't'.

Example 3:

  • Input: s = "welcomeback", t = "ole"
  • Expected Output: "elco"
  • Justification: "elco" includes 'o', 'l', and 'e', fulfilling the requirements with the minimum length.

Solution

To solve this problem, we'll use a sliding window approach combined with a character frequency map. This approach is efficient because it involves scanning the string 's' only once while adjusting the window's start and end to include all characters of 't'.

Initially, we'll create a map to keep track of the frequency of each character in 't'. As we traverse 's', we'll adjust the end of the window to include characters and decrease their frequency in the map. Once all characters from 't' are included in the window, we'll attempt to shrink the window from the start, checking if it still contains all necessary characters. This approach ensures we always have the minimum window containing all characters of 't', which is the core requirement of the problem.

Step-by-step Algorithm

  • Initialize a map to store the frequency of each character in 't'.
  • Use two pointers, start and end, to represent the current window in 's'.
  • Iterate over 's' using the end pointer.
    • For each character in 's' at end, decrease its frequency in the map.
    • Once all characters from 't' are included in the current window (checked via the map), try to shrink the window.
      • Move the start pointer forward while the window still contains all characters from 't'.
    • Update the minimum window size and its starting index when a smaller valid window is found.
  • Return the smallest valid substring from 's' based on the recorded starting index and size. If no such window exists, return an empty string.

Algorithm Walkthrough

Let's take "xyyzyzyx" as 's' and "xyz" as 't'.

Initialization:

  • Map Creation: Create a frequency map for characters in t. Map: {x: 1, y: 1, z: 1}.
  • Variable Initialization: Set start and end to 0, minStart to 0, minLength to a large value (like Integer.MAX_VALUE), and counter to the length of t, which is 3.
  1. First Expansion:

    • end = 0, s[end] = 'x'. Map: {x: 0, y: 1, z: 1}, counter = 2. Window: "x".
  2. Second Expansion:

    • end = 1, s[end] = 'y'. Map: {x: 0, y: 0, z: 1}, counter = 1. Window: "xy".
  3. Third Expansion:

    • end = 2, s[end] = 'y'. Map: {x: 0, y: -1, z: 1}. Window: "xyy".
  4. Fourth Expansion:

    • end = 3, s[end] = 'z'. Map: {x: 0, y: -1, z: 0}, counter = 0. Window: "xyyz".
  5. Start Shrinking:

    • start = 1, s[start - 1] = 'x'. Map: {x: 1, y: -1, z: 0}. Window: "yyz".
  6. Fifth Expansion:

    • end = 4, s[end] = 'y'. Map: {x: 1, y: -2, z: 0}. Window: "yyzy".
  7. Sixth Expansion:

    • end = 5, s[end] = 'z'. Map: {x: 1, y: -2, z: -1}. Window: "yyzyz".
  8. Seventh Expansion:

    • end = 6, s[end] = 'y'. Map: {x: 1, y: -3, z: -1}. Window: "yyzyzy".
  9. Eighth Expansion:

    • end = 7, s[end] = 'x'. Map: {x: 0, y: -3, z: -1}. Window: "yzyzyx".
    • Current window contains all characters of string t. minLength: min(4, 6) = 4, minStart: 2.
    • start is now incremented to find a smaller window containing all characters.
  10. Shrinking Again:

    • Shrink: start=2, end=7, Window: "yzyzyx", Map: {x: 0, y: -2, z: -1}, Counter remains 0.
    • Shrink: start=3, end=7, Window: "zyzyx", Map: {x: 0, y: -1, z: -1}, Counter remains 0.
    • Shrink: start=4, end=7, Window: "yzyx", Map: Map: {x: 0, y: -1, z: 0}, Counter remains 0.
    • Shrink: start=5, end=7, Window: "zyx", Map: {x: 0; y: 0, z: 0}, Counter becomes 1.
    • This is the smallest window that contains all characters of t.

Result:

  • The minimum window substring that contains all characters of t ("xyz") is "zyx".

Code

java
import java.util.*;

public class Solution {

  public String minWindow(String s, String t) {
    if (s == null || t == null || s.length() == 0 || t.length() == 0) {
      return "";
    }

    // Maps character to its frequency in t.
    Map<Character, Integer> map = new HashMap<>();
    for (char c : t.toCharArray()) {
      map.put(c, map.getOrDefault(c, 0) + 1);
    }

    int start = 0, end = 0, minStart = 0, minLength = Integer.MAX_VALUE;
    int counter = t.length(); // Number of characters in t to be found in s.

    while (end < s.length()) {
      char endChar = s.charAt(end);
      // If character in s exists in t, decrease counter.
      if (map.getOrDefault(endChar, 0) > 0) {
        counter--;
      }
      map.put(endChar, map.getOrDefault(endChar, 0) - 1);
      end++;

      // When counter is 0, all characters in t are found in the current window.
      while (counter == 0) {
        if (end - start < minLength) {
          minLength = end - start;
          minStart = start;
        }

        char startChar = s.charAt(start);
        map.put(startChar, map.getOrDefault(startChar, 0) + 1);
        // If character in s exists in t, increase counter.
        if (map.get(startChar) > 0) {
          counter++;
        }
        start++;
      }
    }

    return minLength == Integer.MAX_VALUE
      ? ""
      : s.substring(minStart, minStart + minLength);
  }

  // Main method for testing.
  public static void main(String[] args) {
    Solution solution = new Solution();
    System.out.println(solution.minWindow("xyyzyzyx", "xyz")); // "zyx"
    System.out.println(solution.minWindow("abracadabra", "aa")); // "aca"
    System.out.println(solution.minWindow("welcomeback", "ole")); // "elco"
  }
}

Complexity Analysis

Time Complexity

The time complexity is O(S + T), where S is the length of string s and T is the length of string t.

This is because the algorithm iterates through both strings linearly. The outer loop runs for every character in s, and the inner while loop processes each character only once when shrinking the window.

Space Complexity

The space complexity is O(T), where T is the length of string t.

This complexity arises from the storage required for the frequency map of characters in t. In the worst case, this map will store a distinct entry for each character in t.

🤖 Don't fully get this? Learn it with Claude

Stuck on Minimum Window Substring? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🪜 Hint ladder (no spoilers)

Progressively stronger hints — you still solve it.

I'm working on the problem **Minimum Window Substring** (DSA). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🎨 Explain the approach visually

See the technique, not just code.

Explain the optimal approach to **Minimum Window Substring** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔍 Review my solution

Catch bugs, edge cases, sub-optimality.

I'll paste my solution to **Minimum Window Substring**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔁 Drill the pattern

Lock in recognition with look-alikes.

Give me 2 problems that use the SAME underlying pattern as **Minimum Window Substring**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes