Minimum Window Substring
Problem
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.
Examples
Example 1:
Input: s = "OUZODYXAZV", t = "XYZ"
Output: "YXAZ"
Example 2:
Input: s = "xyz", t = "xyz"
Output: "xyz"
Example 3:
Input: s = "x", t = "xy"
Output: ""
Constraints
1 <= s.length <= 10001 <= t.length <= 1000sandtconsist 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.
Solution
We count how many of each char we need for the input t, and we track how many individual chars have their count met. We start with a sliding window [left, right]. An outer loop moves the right window forward. We track the counts of each char in the current window, and check if we now just matched a required count (make sure to not over count, only check at equality). We then walk the left end of the window forward while the chars_met_count is valid, checking if we found a shorter substring using the length of the window. We remove the char, update the counts, then walk the left index forward.
class Solution {
public:
string minWindow(const string &s, const string &t) {
std::unordered_map<char, int> t_counts;
// Char counts in t
for (const auto &c : t) {
++t_counts[c];
}
const auto num_chars_meet_needed = static_cast<int>(t_counts.size());
std::size_t left = 0;
std::unordered_map<char, int> window_counts;
int num_chars_meet_count = 0;
std::size_t result_len = std::numeric_limits<std::size_t>::max();
std::size_t res_idx_left = 0;
std::size_t res_idx_right = 0;
// Walk sliding window right
for (std::size_t right = 0; right < s.size(); ++right) {
const char c = s[right];
++window_counts[c];
// If we now match required count, track number of chars meeting count
if (t_counts.contains(c) && window_counts[c] == t_counts[c]) {
++num_chars_meet_count;
}
// Walk window left while window is valid, seeing if we find new smallest window
while (num_chars_meet_count == num_chars_meet_needed) {
const char c_removed = s[left];
// Check for better substr
if (right - left + 1 < result_len) {
result_len = right - left + 1;
res_idx_left = left;
res_idx_right = right;
}
// If removing char moves below required count, update tracker
if (t_counts.contains(c_removed) && window_counts[c_removed] == t_counts[c_removed]) {
--num_chars_meet_count;
}
--window_counts[c_removed];
++left;
}
}
return result_len == std::numeric_limits<std::size_t>::max()
? ""
: s.substr(res_idx_left, result_len);
}
};