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.
Example 1:
Input: s = "ADOBECODEBANC", t = "ABC" Output: "BANC" Explanation: The minimum window substring "BANC" includes 'A', 'B', and 'C' from string t.
Example 2:
Input: s = "a", t = "a" Output: "a" Explanation: The entire string s is the minimum window.
Example 3:
Input: s = "a", t = "aa" Output: "" Explanation: Both 'a's from t must be included in the window. Since the largest window of s only has one 'a', return empty string.
Constraints:
m == s.length
n == t.length
1 <= m, n <= 105
s
and t
consist of uppercase and lowercase English letters.
Follow up: Could you find an algorithm that runs in O(m + n)
time?
Problem Statement: Given two strings s
and t
, find the minimum-length substring of s
that contains all the characters of t
(including duplicates). If no such substring exists, return an empty string.
Approach: This problem is efficiently solved using a sliding window technique combined with a frequency counter.
Algorithm:
Frequency Counts: Create two frequency maps (dictionaries or arrays):
need
: Stores the frequency of each character in string t
.window
: Stores the frequency of characters currently within the sliding window in s
.Sliding Window: Initialize two pointers, left
and right
, both starting at index 0. right
will expand the window, while left
will contract it.
Window Expansion: Move right
to the right, adding each character to the window
frequency map.
Valid Window Check: Check if the window
contains all the characters from t
with at least the required frequencies (as specified in need
). This is done by comparing window[char]
>= need[char]
for every character in t
. A counter valid
can track how many characters in need
are satisfied by window
.
Window Contraction: If the window is valid, try to shrink the window from the left (left
pointer). If shrinking the window still maintains a valid window, this optimizes for the smallest possible valid substring. This step is crucial for efficiency.
Update Minimum Window: If a valid window is found, update the min_len
and the start index (min_start
) of the minimum window.
Repeat: Continue expanding (right
) and contracting (left
) until the right
pointer reaches the end of s
.
Time and Space Complexity:
s
and 'n' is the length of `t'. The pointers traverse each string once.Code Implementation (Python):
from collections import defaultdict
def minWindow(s, t):
if not t or not s:
return ""
need = defaultdict(int)
for c in t:
need[c] += 1
window = defaultdict(int)
left, right = 0, 0
valid = 0 # Count of characters in window that meet need
min_len = float('inf')
min_start = -1
while right < len(s):
c = s[right]
right += 1
if c in need: # Only care about characters in t
window[c] += 1
if window[c] == need[c]:
valid += 1
while valid == len(need): # Window contains all characters from t
# Update minimum window if necessary
if right - left < min_len:
min_len = right - left
min_start = left
d = s[left]
left += 1
if d in need:
if window[d] == need[d]:
valid -= 1
window[d] -= 1
return "" if min_start == -1 else s[min_start:min_start + min_len]
# Example usage
s = "ADOBECODEBANC"
t = "ABC"
print(minWindow(s, t)) # Output: "BANC"
s = "a"
t = "a"
print(minWindow(s,t)) # Output: "a"
s = "a"
t = "aa"
print(minWindow(s,t)) # Output: ""
Code Implementation (Other Languages): The approach remains the same; only the syntax and data structure implementations will vary. For example, in Java or C++, you might use HashMap
or arrays for frequency counting. The core logic of the sliding window and the validity check would stay consistent.