Editorial solutions and visualizations are prepared with care, but we do not guarantee 100% accuracy or completeness. Please use your own judgment to verify results. Visucodize is not responsible for decisions made based on this content.
Solution code
constINCLUDED='included',INCLUDED_COLOR='gold';functionvisMainFunction(inputS, inputT){initClassProperties();explanationAndColorSchemaNotifications();startPartialBatch();startBatch();const s = VisArray.from([...inputS]);const t = VisArray.from([...inputT]);const charNeedMap =newVisMap();for(const char of t){
charNeedMap.set(char,(charNeedMap.get(char)||0)+1);}endBatch();notification(`đ <b>Step 1:</b> <code>charNeedMap</code> is initialized with the frequency of each character in <b>t</b>.
Since the window is initially empty, every required character is still missing from the current window.`);let left =0;let minLength =Infinity;let minStart =0;let requiredUniqueCount = charNeedMap.size;let fulfilledUniqueCount =0;makeVisVariable(minLength).options({label:'minLength'}).createVis();makeVisVariable(minStart).options({label:'minStart'}).createVis();makeVisVariable(requiredUniqueCount).options({label:'requiredUniqueCount'}).createVis();makeVisVariable(fulfilledUniqueCount).options({label:'fulfilledUniqueCount'}).createVis();endBatch();for(let right =0; right < s.length; right++){startPartialBatch();highlightIndex(s, right);const rightChar = s[right];if(charNeedMap.has(rightChar)){notification(`đ <b>Right Pointer at index ${right}:</b> Found <b>"${rightChar}"</b>, one of the required target characters.
Decreasing its remaining count in <code>charNeedMap</code>.`);
charNeedMap.set(rightChar, charNeedMap.get(rightChar)-1);if(charNeedMap.get(rightChar)===0){
fulfilledUniqueCount++;notification(`â <b>Fully fulfilled character:</b> <b>"${rightChar}"</b> is now completely covered in the current window.`);while(fulfilledUniqueCount === requiredUniqueCount){const windowLength = right - left +1;notification(`đ¯ <b>Valid window detected (length = ${windowLength})!</b> Checking if this is the smallest valid window before attempting to shrink it further.`);if(windowLength < minLength){
minLength = windowLength;
minStart = left;notification(`đ <b>New Minimum Window Found:</b> Starts at index <b>${minStart}</b> with length <b>${minLength}</b>.`);}else{notification(`âšī¸ <b>Current window length (${windowLength})</b> is not smaller than the previous minimum (<b>${minLength}</b>), so the minimum remains unchanged.`);}notification(`đ <b>Moving <code>left</code> forward</b> to try finding a smaller valid window that still covers all required characters.`);const leftChar = s[left];unhighlightIndex(s, left);if(charNeedMap.has(leftChar)){if(charNeedMap.get(leftChar)===0){
fulfilledUniqueCount--;notification(`â ī¸ <b>Lost a fully fulfilled character:</b> <b>"${leftChar}"</b> is no longer completely fulfilled, making the window invalid.`);}
charNeedMap.set(leftChar, charNeedMap.get(leftChar)+1);}
left++;}}}endBatch();}notification(`đ <b>Finished!</b> The minimum window substring is <b>"${minLength ===Infinity?"": inputS.substring(minStart, minStart + minLength)}"</b>.`);return minLength ===Infinity?"": inputS.substring(minStart, minStart + minLength);}functionhighlightIndex(arr, index){
arr.makeVisManagerForIndex(index).addClass(INCLUDED);}functionunhighlightIndex(arr, index){
arr.makeVisManagerForIndex(index).removeClass(INCLUDED);}functioninitClassProperties(){setClassProperties(INCLUDED,{backgroundColor:INCLUDED_COLOR});}functionexplanationAndColorSchemaNotifications(){explanationNotification();notification(`
đ¨ <b>Color Schema:</b><br>
<span class='${INCLUDED}' style='background:${INCLUDED_COLOR};color:black;'>gold background</span> â
Marks the characters in <b>s</b> that are currently <b>included in the active window</b>
as we expand or shrink the sliding window.
`);}
Solution explanation
Solution explanation
Approach
The Minimum Window Substring problem is solved using the Sliding Window technique with two pointers (left and right) and a frequency map charNeedMap that tracks how many of each target character are still required.
We maintain requiredUniqueCount and fulfilledUniqueCount to determine when the current window satisfies all required characters.
The algorithm gradually expands the window by moving right to include new characters until it becomes valid â meaning all characters from t are covered.
Once valid, it shrinks the window by moving left forward while the condition remains satisfied, discarding unnecessary characters to find the shortest valid substring.
Core data structures / variables:
charNeedMap: a hashmap of remaining requirements for each character in t.
Initialized from frequencies of t (since the window is initially empty, every required character is still missing from the current window).
A value > 0 means we still need that many of the character;
a value = 0 means the requirement for that character is exactly satisfied;
a value < 0 means the window currently has more than required (which is allowed).
left: start index of the current window.
right: end index of the current window.
requiredUniqueCount = charNeedMap.size: the number of distinct characters from t that must be fully satisfied.
fulfilledUniqueCount: how many of those distinct requirements are currently fully satisfied (their need count is 0).
minLength: length of the best (shortest) valid window found so far (start with Infinity).
minStart: starting index of that best window.
Algorithm flow:
Initialization: Build charNeedMap from t. Set left = 0, minLength = Infinity, minStart = 0, fulfilledUniqueCount = 0.
For each right from 0 to s.length - 1:
Let rightChar = s[right].
If rightChar is in charNeedMap (meaning that it is one of the required target characters):
Decrement charNeedMap[rightChar].
If the need for rightChar becomes exactly 0 (meaning rightChar is now completely covered in the current window), then:
Increment fulfilledUniqueCount
While window is valid (fulfilledUniqueCount === requiredUniqueCount):
Update the best answer: if right - left + 1 < minLength, set minLength and minStart.
Try to shrink the window:
Let leftChar = s[left]. If leftChar exists in charNeedMap, increment charNeedMap[leftChar].
If this changes its count from 0 â 1, a fully satisfied requirement is lost â decrement fulfilledUniqueCount, making the window invalid.
Increment left.
Result: If minLength === Infinity, no window exists â return "". Otherwise, return s.substring(minStart, minStart + minLength).
Time Complexity
Let n be the length of s and m be the length of t.
The algorithm runs in O(n + m) time:
Build need map: Initializing charNeedMap from t takes O(m).
Single pass over s: The right pointer advances from 0 to n â 1 once,
and the left pointer also moves forward at most n times in total.
Each pointer update involves constant-time map operations. Therefore, this phases takes O(n).
Therefore: the total time complexity is O(n + m).
Space Complexity
The algorithm uses O(k) auxiliary space, where k is the number of distinct characters in t:
Need map:charNeedMap stores at most one entry per unique character in t,
resulting in O(k) space usage.
Other variables: Scalars such as left, right, minLength, minStart,
requiredUniqueCount, and fulfilledUniqueCount use O(1) space.
Since both s and t consist of uppercase and lowercase English letters,
the total number of possible unique characters is 52 (AâZ, aâz), which is a fixed constant.
Therefore, the overall auxiliary space simplifies to O(1).
Input-1
Visucodize editorial solution titled JS Solution for LeetCode's Minimum Window Substring coding problem. Includes code and may include explanation. You can animate the code step by step using the provided input by clicking the run button, or fork it locally to update the code and input for custom visualization. View the original problem at https://leetcode.com/problems/minimum-window-substring.