Minimum Window Substring in DSA C++ - Time & Space Complexity
We want to understand how the time needed to find the smallest substring containing all characters of another string changes as the input grows.
How does the running time grow when the input strings get longer?
Analyze the time complexity of the following code snippet.
string minWindow(string s, string t) {
unordered_map<char, int> need, window;
for (char c : t) need[c]++;
int left = 0, right = 0, valid = 0;
int start = 0, len = INT_MAX;
while (right < s.size()) {
char c = s[right++];
if (need.count(c)) {
window[c]++;
if (window[c] == need[c]) valid++;
}
while (valid == need.size()) {
if (right - left < len) {
start = left;
len = right - left;
}
char d = s[left++];
if (need.count(d)) {
if (window[d] == need[d]) valid--;
window[d]--;
}
}
}
return len == INT_MAX ? "" : s.substr(start, len);
}
This code finds the smallest substring in s that contains all characters of t.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The
whileloop that movesrightpointer through strings, and the innerwhileloop that movesleftpointer to shrink the window. - How many times: Each character in
sis visited at most twice: once whenrightmoves forward, once whenleftmoves forward.
As the input string s grows, the pointers move through it mostly once each, so the operations grow roughly in proportion to the length of s.
| Input Size (n = length of s) | Approx. Operations |
|---|---|
| 10 | About 20 moves of pointers |
| 100 | About 200 moves of pointers |
| 1000 | About 2000 moves of pointers |
Pattern observation: The number of operations grows roughly linearly with input size.
Time Complexity: O(n + m)
This means the time grows linearly with the size of both input strings s and t.
[X] Wrong: "Because there are nested loops, the time must be quadratic O(n²)."
[OK] Correct: The inner loop moves the left pointer forward only when the outer loop moves right, so each pointer moves at most n times, making it linear, not quadratic.
Understanding this sliding window approach and its linear time complexity shows you can handle efficient substring problems, a common skill interviewers look for.
"What if we replaced the unordered_map with a fixed-size array for characters? How would the time complexity change?"
Practice
Minimum Window Substring problem?Solution
Step 1: Understand the problem statement
The problem asks to find the smallest substring in a given string that contains all characters of another string, including duplicates.Step 2: Compare with other substring problems
Unlike longest substring or counting substrings, this problem focuses on minimum length substring covering all required characters.Final Answer:
Find the smallest substring in a string that contains all characters of another string -> Option DQuick Check:
Minimum window substring = smallest substring with all chars [OK]
- Confusing with longest substring problems
- Ignoring duplicate characters in target string
- Thinking it's about sorting or counting substrings
Solution
Step 1: Identify the need for character frequency tracking
We need to count how many times each character appears in the target string and track them in the window.Step 2: Choose container supporting key-value pairs with fast access
std::unordered_map allows mapping characters to counts with average O(1) access, ideal for this purpose.Final Answer:
std::unordered_map<char, int> -> Option AQuick Check:
Use unordered_map for char counts [OK]
- Using stack or queue which don't support key-value mapping
- Using vector without mapping char to index
- Using map which is slower than unordered_map
s = "ADOBECODEBANC" and t = "ABC"?
std::string minWindow(std::string s, std::string t) {
std::unordered_map dictT;
for (char c : t) dictT[c]++;
int required = dictT.size();
int l = 0, r = 0, formed = 0;
std::unordered_map windowCounts;
int minLen = INT_MAX, minLeft = 0;
while (r < s.size()) {
char c = s[r];
windowCounts[c]++;
if (dictT.count(c) && windowCounts[c] == dictT[c]) formed++;
while (l <= r && formed == required) {
if (r - l + 1 < minLen) {
minLen = r - l + 1;
minLeft = l;
}
windowCounts[s[l]]--;
if (dictT.count(s[l]) && windowCounts[s[l]] < dictT[s[l]]) formed--;
l++;
}
r++;
}
return minLen == INT_MAX ? "" : s.substr(minLeft, minLen);
}
std::cout << minWindow("ADOBECODEBANC", "ABC") << std::endl;Solution
Step 1: Understand the sliding window approach
The code expands the right pointer to include characters and contracts the left pointer to find the smallest window containing all chars of t.Step 2: Trace the window updates for s="ADOBECODEBANC" and t="ABC"
The smallest substring containing 'A', 'B', and 'C' is "BANC" starting at index 9 with length 4.Final Answer:
BANC -> Option BQuick Check:
Minimum window substring = BANC [OK]
- Choosing first found substring instead of minimum
- Ignoring character counts and duplicates
- Confusing substring indices
std::string minWindow(std::string s, std::string t) {
std::unordered_map dictT;
for (char c : t) dictT[c]++;
int required = dictT.size();
int l = 0, r = 0, formed = 0;
std::unordered_map windowCounts;
int minLen = INT_MAX, minLeft = 0;
while (r < s.size()) {
char c = s[r];
windowCounts[c]++;
if (dictT.count(c) && windowCounts[c] == dictT[c]) formed++;
while (l <= r && formed == required) {
if (r - l + 1 < minLen) {
minLen = r - l + 1;
minLeft = l;
}
windowCounts[s[l]]--;
if (dictT.count(s[l]) && windowCounts[s[l]] < dictT[s[l]]) formed--;
l++;
}
// Missing increment of r here
}
return minLen == INT_MAX ? "" : s.substr(minLeft, minLen);
}Solution
Step 1: Analyze the while loop controlling 'r'
The loop uses 'r' to expand the window, but 'r' is never incremented inside the loop, causing an infinite loop.Step 2: Identify missing increment
Without 'r++' inside the loop, the window never expands, so the function cannot find the minimum window.Final Answer:
The right pointer 'r' is never incremented inside the loop -> Option AQuick Check:
Missing r++ causes infinite loop [OK]
- Forgetting to increment pointers in loops
- Misusing condition checks for formed variable
- Not updating window counts correctly
s = "aabbccdd" and t = "abc", which of the following modifications to the standard Minimum Window Substring algorithm will correctly find the minimum window containing all characters of t even if t has duplicate characters like "aabc"?Solution
Step 1: Understand the importance of duplicates in
Ifttcontains duplicates, the algorithm must count how many times each character appears and ensure the window matches those counts.Step 2: Modify frequency tracking to include exact counts
Using a frequency map fortand comparing window counts exactly ensures duplicates are handled correctly.Final Answer:
Use a frequency map for t and check counts exactly, including duplicates -> Option CQuick Check:
Exact frequency counts handle duplicates [OK]
- Ignoring duplicate characters in target string
- Using sets which lose count information
- Checking only presence, not frequency
Ready to prove it?
Pass the test and this pattern moves unknown
