76. Minimum Window Substring#
Difficulty: Hard
Link to Problem: To see the Minimum Window Substring problem on LeetCode, click here!
Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no such substring, return the empty string "".
The testcases will be generated such that the answer is unique.
Constraints:
m == s.lengthn == t.length1 <=
m, n<= \(10^5\)sandtconsist of uppercase and lowercase English letters.
Follow up: Could you find an algorithm that runs in \(O(m + n)\) time?
def min_window_substring(s, t):
if not s or not t:
return ""
# Initialize dictionaries to keep track of character counts for t and the current window in s.
t_dict = {}
current_window_dict = {}
# Populate t_dict with character counts for string t.
for char in t:
t_dict[char] = t_dict.get(char, 0) + 1
# Initialize pointers for the sliding window.
left = 0
min_len = float('inf')
min_window = ""
required_chars = len(t_dict)
# Initialize a variable to keep track of how many required characters have been found in the current window.
found_chars = 0
# Iterate over the string s using the right pointer.
for right in range(len(s)):
char = s[right]
# Update the current_window_dict.
current_window_dict[char] = current_window_dict.get(char, 0) + 1
# Check if the current character is a required character and if its count matches the required count.
if char in t_dict and current_window_dict[char] == t_dict[char]:
found_chars += 1
# Try to minimize the window by moving the left pointer.
while left <= right and found_chars == required_chars:
# Calculate the current window size.
window_size = right - left + 1
# If the current window is smaller than the minimum found so far, update min_len and min_window.
if window_size < min_len:
min_len = window_size
min_window = s[left:right+1]
# Move the left pointer to the right to shrink the window.
left_char = s[left]
current_window_dict[left_char] -= 1
# Check if the character removed from the window was a required character.
if left_char in t_dict and current_window_dict[left_char] < t_dict[left_char]:
found_chars -= 1
# Move the left pointer further to continue shrinking the window.
left += 1
return min_window
Explanation:#
We start by checking if either of the input strings
sortis empty. If either of them is empty, we return an empty string since there can’t be any valid substring in this case.We initialize two dictionaries:
t_dictandcurrent_window_dict. These dictionaries will be used to keep track of character counts in the stringtand the current window in strings, respectively.We populate the
t_dictdictionary by iterating through stringt. For each character, we increment its count in the dictionary usingt_dict.get(char, 0) + 1. This allows us to count the occurrences of each character int.We initialize two pointers:
leftandright. Theleftpointer will represent the start of the current window, and therightpointer will represent the end of the current window. We also initializemin_lento store the length of the minimum window found so far, andmin_windowto store the actual minimum window substring.We determine the number of required characters in
t(i.e., the number of distinct characters int) and store it in the variablerequired_chars.We initialize a variable
found_charsto keep track of how many required characters have been found in the current window. Initially, it is set to 0.We iterate over the string
susing therightpointer. In each iteration, we do the following:Update the
current_window_dictby incrementing the count of the current character.Check if the current character is a required character (present in
t_dict) and if its count in thecurrent_window_dictmatches the required count fromt_dict. If so, we incrementfound_chars.
After updating the window, we attempt to minimize the window size by moving the
leftpointer to the right. In this step, we:Calculate the size of the current window.
If the current window size is smaller than the minimum found so far (
min_len), we updatemin_lenandmin_windowto store the current window substring.Move the
leftpointer to the right to shrink the window.Check if the character being removed from the window was a required character. If it was, we decrement
found_chars.Continue moving the
leftpointer further to continue shrinking the window if the window still contains all required characters.
Finally, we return
min_window, which will contain the minimum window substring that contains all characters fromt.
Test cases#
# Example 1:
print(min_window_substring("ADOBECODEBANC", "ABC"))
BANC
# Example 2:
print(min_window_substring("a", "a"))
a
# Example 3:
print(min_window_substring("a", "aa"))
Let’s analyze the time and space complexity of the min_window_substring function:
Time Complexity:
The main loop iterates through the string
sfrom left to right using therightpointer. This loop runs in O(m) time, where ‘m’ is the length of strings.Inside the loop, we have a while loop that moves the
leftpointer to the right to shrink the window as needed. In the worst case, this while loop can also run in O(m) time because in the worst case, we may have to move theleftpointer all the way to the end of the string.Within each iteration of the while loop, we perform constant time operations, such as updating dictionaries and comparing character counts.
The initialization of the
t_dictdictionary takes O(n) time, where ‘n’ is the length of stringt.
Therefore, the overall time complexity of the function is O(m + n) because the dominant factor is the length of string s, and the length of string t has a smaller impact.
Space Complexity:
The space complexity is determined by the space used by the
t_dictdictionary, thecurrent_window_dictdictionary, and a few variables.The
t_dictdictionary stores character counts for stringt. In the worst case, when all characters intare distinct, this dictionary can have a maximum of ‘n’ key-value pairs. So, the space complexity fort_dictis O(n).The
current_window_dictdictionary stores character counts for the current window. In the worst case, it can have a maximum of ‘m’ key-value pairs. So, the space complexity forcurrent_window_dictis also O(m).Other variables used in the function, such as
left,right,min_len,min_window,required_chars, andfound_chars, are all of constant size and do not depend on the input sizes.
In summary, the overall space complexity of the function is O(max(m, n)), which means it is determined by the larger of the two input strings’ lengths. This is because the space used for t_dict and current_window_dict dominates the space complexity.
Challenging Exercises:#
Smallest Distinct Substring: Instead of finding the minimum window substring containing all characters, find the smallest distinct (unique) substring of s that contains all characters from t. This variation adds complexity because you must find a substring with distinct characters.
No Extra Space: Solve the problem without using any extra space, such as dictionaries or arrays, other than a constant amount of space. This is a significant optimization challenge.