diff --git a/apps/docs/content/(hash-table)/3-longest-substring-without-repeating-characters.mdx b/apps/docs/content/(hash-table)/3-longest-substring-without-repeating-characters.mdx new file mode 100644 index 0000000..b0f4f83 --- /dev/null +++ b/apps/docs/content/(hash-table)/3-longest-substring-without-repeating-characters.mdx @@ -0,0 +1,47 @@ +--- +title: '3. Longest Substring Without Repeating Characters' +description: Given a string s, find the length of the longest substring without duplicate characters +sidebar: + label: 'Longest Substring Without Repeating Characters' + badge: 'Medium' +--- + +Sliding Window + +### Example 1: +- Input: `s = "abcabcbb"` +- Output: `3` +- Explanation: The answer is "abc", with the length of `3`. Note that "bca" and "cab" are also correct answers. + +### Example 2: +- Input: `s = "bbbbb"` +- Output: `1` +- Explanation: The answer is "b", with the length of `1`. + +### Example 3: +- Input: `s = "pwwkew"` +- Output: `3` +- Explanation: The answer is "wke", with the length of `3`. Notice that the answer must be a substring, "pwke" is a subsequence and not a substring. + +### Constraints: + +- `0 <= s.length <= 10^5` +- `s` consists of English letters, digits, symbols and spaces. + +## Solution + +```py +class Solution: + def lengthOfLongestSubstring(self, s: str) -> int: + left = 0 + ans = 0 + seen = set() + for right, c in enumerate(s): + while c in seen: + seen.remove(s[left]) + left += 1 + seen.add(c) + ans = max(ans, right - left + 1) + + return ans +``` diff --git a/apps/docs/content/reference/sliding-window.mdx b/apps/docs/content/reference/sliding-window.mdx new file mode 100644 index 0000000..8b6285d --- /dev/null +++ b/apps/docs/content/reference/sliding-window.mdx @@ -0,0 +1,103 @@ +--- +title: Sliding Window +description: 'Sliding window is a specialized two-pointer family where the pointers define a contiguous interval and you maintain information about that entire interval as it moves.' +--- + +:::warning +This is the family where invariants matter the most +::: + +## What Makes Sliding Window Different? + +Many problems have two moving boundaries. That alone does not make them sliding window problems. + +A problem belongs to this family when: + +- the answer depends on the subarray or substring between left and right +- you can update the window state incrementally as elements enter or leave +- you maintain a condition that tells you whether the window is valid + +## What is an Invariant? + + +An invariant is a statement that stays true before and after every iteration. + +For sliding window, the invariant often looks like one of these: + +- "the current window is valid" +- "the current window contains no duplicates" +- "the current window sum is at most the target" +- "the frequency map matches the characters currently inside the window" + +The invariant gives the loop its structure: + +- expand the window by moving right +- update the window state +- if the invariant breaks, shrink from the left until it holds again +- update the answer only when you know the invariant is satisfied + + +## Why Invariants Matter + +Without an invariant, shrinking the window becomes arbitrary. You no longer know: + +- when the window is valid +- when to update the answer +- why the left pointer should stop moving +- The invariant is the reason the algorithm is correct. + +## The Main Subtypes + +### 1. Fixed-size windows + +:::tip +The window size never changes. The main task is updating the window state efficiently when one element enters and one leaves. +::: + +![Sliding Window Fixed Size](../../public/sliding-window-fixed-size.svg) + +### 2. Flexible-size windows with a validity rule + +:::tip +Here the window expands until invalid, then shrinks until valid again. +::: + +![Flexible-size windows](../../public/sliding-window-flexible.svg) + + +### 3. Frequency-tracking windows + +:::tip +The difficulty comes from keeping the bookkeeping correct as characters enter and leave. +::: + +![Frequency-tracking windows](../../public/sliding-window-frequency.svg) + +## How Sliding Window Differs From Other Two-Pointer Families + +Compare it with Container With Most Water: + +- In sliding window, the interval itself has meaning. +- In container, the interval is just the remaining search space. + +Compare it with Remove Duplicates: + +- In sliding window, both pointers describe a live window. +- In compaction, the left part of the array is already the answer prefix. + +## A Practical Template + +A common variable-size sliding window has this shape: + +1. Add the new rightmost element. +2. Update the window state. +3. While the invariant is broken, remove elements from the left. +4. Once the invariant is restored, update the answer. + +The exact data structure changes from problem to problem, but the logic stays the same. + +As you work through this section, keep asking: + +:::warning +What invariant does my window maintain, and at what moment is it safe to update the answer? +::: diff --git a/apps/docs/public/sliding-window-fixed-size.svg b/apps/docs/public/sliding-window-fixed-size.svg new file mode 100644 index 0000000..b497628 --- /dev/null +++ b/apps/docs/public/sliding-window-fixed-size.svg @@ -0,0 +1,66 @@ + + + + + + Sliding Window: Fixed Size + Window of size K=3 moving through the array. + + + + 1. Current window (Sum = 10) + + + + + 2 + + + 3 + + + 5 + + + 1 + + + 8 + + + + + + + + + + Slide window: -2, +1 + + + + + 2. Next window (Sum = 9) + + + + + 2 + + + 3 + + + 5 + + + 1 + + + 8 + + + + + + diff --git a/apps/docs/public/sliding-window-flexible.svg b/apps/docs/public/sliding-window-flexible.svg new file mode 100644 index 0000000..048b407 --- /dev/null +++ b/apps/docs/public/sliding-window-flexible.svg @@ -0,0 +1,66 @@ + + + + + + Sliding Window: Flexible Size + Window expands until invalid, then shrinks until valid again. + + + + 1. Expansion breaks invariant + + + + + a + + L + + + b + + + c + + + a + + R + + Duplicate 'a'! + + + + + + + Shrink from left + + + + + 2. Invariant restored + + + + + a + + + b + + L + + + c + + + a + + R + + Valid again! + + + diff --git a/apps/docs/public/sliding-window-frequency.svg b/apps/docs/public/sliding-window-frequency.svg new file mode 100644 index 0000000..0e8d5cf --- /dev/null +++ b/apps/docs/public/sliding-window-frequency.svg @@ -0,0 +1,54 @@ + + + + + + Sliding Window: Frequency Tracking + Maintaining a character frequency map for the current window. + + + + Current Window + + + + + a + + L + + + b + + + a + + R + + + c + + + + + + Frequency Map + + + + + + + 'a' : 2 + 'b' : 1 + 'c' : 0 + + + + + INVARIANT: SYNCED STATE + + + + +