Minimum window substring
Grow the window on the right until it contains everything, then shrink it from the left while it still does. The trick that keeps it O(n) is tracking a single count of unsatisfied characters rather than comparing two dictionaries on every step.
Overview
The grow-then-shrink shape
Two phases alternating. Extend hi until the window satisfies the requirement; then advance lo as far as possible while it still does, recording the best window each time. When it stops being valid, go back to growing.
Every index is entered once by hi and left once by lo, so the total work is O(n) despite the nested loop. That is the same amortised argument as longest-substring-without-repeats and longest-consecutive-sequence — a nested loop is not automatically quadratic.
Step through it
What to watch
- The window grows on the right and shrinks on the left — never the reverse.
- Shrinking continues while the window is still valid, not just once.
- Both pointers move forward only, which is what makes it linear.
Say this out loud
"Sliding window: expand right until the window is valid, then contract left while it stays valid, recording the best. I keep a counter of how many required characters are still short, so checking validity is one integer comparison rather than a dict comparison. O(n)."