Given two strings s and t, return the shortest substring of s such that every character in t, including duplicates, is present in the substring. If such a substring does not exist, return an empty string "".
You may assume that the correct output is always unique.
Example 1:
Input: s = "OUZODYXAZV", t = "XYZ"
Output: "YXAZ"Explanation: "YXAZ" is the shortest substring that includes "X", "Y", and "Z" from string t.
Example 2:
Input: s = "xyz", t = "xyz"
Output: "xyz"Example 3:
Input: s = "x", t = "xy"
Output: ""Constraints:
1 <= s.length <= 10001 <= t.length <= 1000s and t consist of uppercase and lowercase English letters.
You should aim for a solution with O(n) time and O(m) space, where n is the length of the string s and m is the number of unique characters in s and t.
A brute force solution would involve checking every substring of s against t and returning the minimum length valid substring. This would be an O(n^2) solution. Can you think of a better way? Maybe you should think in terms of frequency of characters.
We need to find substrings in s that should have atleast the characters of t. We can use hash maps to maintain the frequencies of characters. It will be O(1) for lookups. Can you think of an algorithm now?
We can use a dynamically sized sliding window approach on s. We iterate through s while maintaining a window. If the current window contains at least the frequency of characters from t, we update the result and shrink the window until it is valid.
We should ensure that we maintain the result substring and only update it if we find a shorter valid substring. Additionally, we need to keep track of the result substring's length so that we can return an empty string if no valid substring is found.
Before attempting this problem, you should be comfortable with:
We want the smallest substring of s that contains all characters of t (with the right counts).
The brute-force way is to try every possible substring of s and check whether it covers all the characters in t.
For each starting index, we expand the end index and keep a frequency map for the current substring.
Whenever the substring has all required characters, we see if it's the smallest one so far.
This is simple to understand but very slow because we check many overlapping substrings.
t is empty, return an empty string.countT for all characters in t.res = [-1, -1] to store the best window,resLen = infinity to store the smallest length found.i in s:countS.j from i to the end of s:s[j] to countS.i to j contains all characters in t:c in countT, ensure countS[c] is at least countT[c].res and resLen.resLen is still infinity, return "".s[res[0] : res[1] + 1].class Solution:
def minWindow(self, s: str, t: str) -> str:
if t == "":
return ""
countT = {}
for c in t:
countT[c] = 1 + countT.get(c, 0)
res, resLen = [-1, -1], float("infinity")
for i in range(len(s)):
countS = {}
for j in range(i, len(s)):
countS[s[j]] = 1 + countS.get(s[j], 0)
flag = True
for c in countT:
if countT[c] > countS.get(c, 0):
flag = False
break
if flag and (j - i + 1) < resLen:
resLen = j - i + 1
res = [i, j]
l, r = res
return s[l : r + 1] if resLen != float("infinity") else ""Where is the length of the string and is the total number of unique characters in the strings and .
We want the smallest window in s that contains all characters of t (with the right counts).
Instead of checking all substrings, we use a sliding window:
r and adding characters into a window map.t), we try to shrink it from the left with pointer l to make it as small as possible while still valid.During this process, we keep track of the best (smallest) window seen so far.
This way, we only scan each character at most two times, making it efficient and still easy to follow.
t is empty, return "".countT for characters in t.window as an empty map for the current window counts.have = 0 = how many characters currently meet the required count.need = len(countT) = how many distinct characters we need to match.res = [-1, -1] and resLen = infinity to store the best window.r to expand the window over s:s[r] to window.s[r] is in countT and its count in window matches countT, increment have.have == need, the window is valid:s[l] in window.s[l] is in countT and its count in window falls below countT, decrement have.l right.res if found; otherwise, return "".class Solution:
def minWindow(self, s: str, t: str) -> str:
if t == "":
return ""
countT, window = {}, {}
for c in t:
countT[c] = 1 + countT.get(c, 0)
have, need = 0, len(countT)
res, resLen = [-1, -1], float("infinity")
l = 0
for r in range(len(s)):
c = s[r]
window[c] = 1 + window.get(c, 0)
if c in countT and window[c] == countT[c]:
have += 1
while have == need:
if (r - l + 1) < resLen:
res = [l, r]
resLen = r - l + 1
window[s[l]] -= 1
if s[l] in countT and window[s[l]] < countT[s[l]]:
have -= 1
l += 1
l, r = res
return s[l : r + 1] if resLen != float("infinity") else ""Where is the length of the string and is the total number of unique characters in the strings and .
The target string t may contain duplicate characters (e.g., "AAB"). Simply checking for character presence is insufficient; you must track the exact count of each character and ensure the window contains at least that many occurrences.
When contracting the window from the left, some implementations remove characters before checking if the window is still valid. Always update the result before shrinking, and only shrink while the window remains valid.
Using have == need requires careful management: have should only increment when a character's count exactly reaches the required amount, and only decrement when it falls below. Incrementing have every time a required character is added leads to overcounting.
When t is empty, the minimum window is an empty string. Failing to handle this edge case at the start can lead to unexpected behavior or incorrect results.
When storing and returning the result window, confusing inclusive vs. exclusive bounds leads to returning a substring that is one character too short or too long. Ensure consistency between how you store indices and how you extract the final substring.