mirror of
https://github.com/prdlk/leetcode.git
synced 2026-09-16 23:16:26 +00:00
docs(docs): add longest‑substring problem page and sliding‑window reference with SVG illustrations
This commit is contained in:
@@ -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'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Sliding Window</Badge>
|
||||
|
||||
### 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
|
||||
```
|
||||
@@ -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.
|
||||
:::
|
||||
|
||||

|
||||
|
||||
### 2. Flexible-size windows with a validity rule
|
||||
|
||||
:::tip
|
||||
Here the window expands until invalid, then shrinks until valid again.
|
||||
:::
|
||||
|
||||

|
||||
|
||||
|
||||
### 3. Frequency-tracking windows
|
||||
|
||||
:::tip
|
||||
The difficulty comes from keeping the bookkeeping correct as characters enter and leave.
|
||||
:::
|
||||
|
||||

|
||||
|
||||
## 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?
|
||||
:::
|
||||
@@ -0,0 +1,66 @@
|
||||
<svg viewBox="0 0 800 450" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Background (REQUIRED) -->
|
||||
<rect width="800" height="450" fill="#f8f9fa" rx="10"/>
|
||||
|
||||
<!-- Title and Subtitle -->
|
||||
<text x="400" y="45" font-family="Arial, sans-serif" font-size="26" font-weight="bold" fill="#2c3e50" text-anchor="middle">Sliding Window: Fixed Size</text>
|
||||
<text x="400" y="75" font-family="Arial, sans-serif" font-size="16" fill="#7f8c8d" text-anchor="middle">Window of size K=3 moving through the array.</text>
|
||||
|
||||
<!-- Step 1: Initial window -->
|
||||
<g transform="translate(150, 130)">
|
||||
<text x="0" y="-20" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="#2c3e50">1. Current window (Sum = 10)</text>
|
||||
|
||||
<!-- Array -->
|
||||
<g transform="translate(0, 20)">
|
||||
<rect x="0" y="0" width="60" height="50" fill="#d1fae5" stroke="#10b981" stroke-width="3" rx="3"/>
|
||||
<text x="30" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#1b5e20">2</text>
|
||||
|
||||
<rect x="70" y="0" width="60" height="50" fill="#d1fae5" stroke="#10b981" stroke-width="3" rx="3"/>
|
||||
<text x="100" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#1b5e20">3</text>
|
||||
|
||||
<rect x="140" y="0" width="60" height="50" fill="#d1fae5" stroke="#10b981" stroke-width="3" rx="3"/>
|
||||
<text x="170" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#1b5e20">5</text>
|
||||
|
||||
<rect x="210" y="0" width="60" height="50" fill="#ffffff" stroke="#dee2e6" stroke-width="2" rx="3"/>
|
||||
<text x="240" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">1</text>
|
||||
|
||||
<rect x="280" y="0" width="60" height="50" fill="#ffffff" stroke="#dee2e6" stroke-width="2" rx="3"/>
|
||||
<text x="310" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">8</text>
|
||||
|
||||
<!-- Bracket -->
|
||||
<path d="M 0,60 L 0,70 L 200,70 L 200,60" fill="none" stroke="#10b981" stroke-width="2"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- Transition -->
|
||||
<g transform="translate(400, 260)">
|
||||
<path d="M 0,0 L 0,30" stroke="#dee2e6" stroke-width="2" fill="none"/>
|
||||
<text x="10" y="20" font-family="Arial, sans-serif" font-size="14" font-style="italic" fill="#7f8c8d">Slide window: -2, +1</text>
|
||||
</g>
|
||||
|
||||
<!-- Step 2: Slid window -->
|
||||
<g transform="translate(150, 340)">
|
||||
<text x="0" y="-20" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="#2c3e50">2. Next window (Sum = 9)</text>
|
||||
|
||||
<!-- Array -->
|
||||
<g transform="translate(0, 20)">
|
||||
<rect x="0" y="0" width="60" height="50" fill="#e5e7eb" stroke="#94a3b8" stroke-width="2" rx="3"/>
|
||||
<text x="30" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#94a3b8">2</text>
|
||||
|
||||
<rect x="70" y="0" width="60" height="50" fill="#d1fae5" stroke="#10b981" stroke-width="3" rx="3"/>
|
||||
<text x="100" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#1b5e20">3</text>
|
||||
|
||||
<rect x="140" y="0" width="60" height="50" fill="#d1fae5" stroke="#10b981" stroke-width="3" rx="3"/>
|
||||
<text x="170" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#1b5e20">5</text>
|
||||
|
||||
<rect x="210" y="0" width="60" height="50" fill="#d1fae5" stroke="#10b981" stroke-width="3" rx="3"/>
|
||||
<text x="240" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#1b5e20">1</text>
|
||||
|
||||
<rect x="280" y="0" width="60" height="50" fill="#ffffff" stroke="#dee2e6" stroke-width="2" rx="3"/>
|
||||
<text x="310" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">8</text>
|
||||
|
||||
<!-- Bracket -->
|
||||
<path d="M 70,60 L 70,70 L 270,70 L 270,60" fill="none" stroke="#10b981" stroke-width="2"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,66 @@
|
||||
<svg viewBox="0 0 800 450" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Background (REQUIRED) -->
|
||||
<rect width="800" height="450" fill="#f8f9fa" rx="10"/>
|
||||
|
||||
<!-- Title and Subtitle -->
|
||||
<text x="400" y="45" font-family="Arial, sans-serif" font-size="26" font-weight="bold" fill="#2c3e50" text-anchor="middle">Sliding Window: Flexible Size</text>
|
||||
<text x="400" y="75" font-family="Arial, sans-serif" font-size="16" fill="#7f8c8d" text-anchor="middle">Window expands until invalid, then shrinks until valid again.</text>
|
||||
|
||||
<!-- Step 1: Invalid state -->
|
||||
<g transform="translate(150, 130)">
|
||||
<text x="0" y="-20" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="#2c3e50">1. Expansion breaks invariant</text>
|
||||
|
||||
<!-- Array -->
|
||||
<g transform="translate(0, 20)">
|
||||
<rect x="0" y="0" width="60" height="50" fill="#fee2e2" stroke="#ef4444" stroke-width="3" rx="3"/>
|
||||
<text x="30" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">a</text>
|
||||
<polygon points="30,60 25,70 35,70" fill="#27ae60"/>
|
||||
<text x="30" y="85" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#27ae60" text-anchor="middle">L</text>
|
||||
|
||||
<rect x="70" y="0" width="60" height="50" fill="#fee2e2" stroke="#ef4444" stroke-width="3" rx="3"/>
|
||||
<text x="100" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">b</text>
|
||||
|
||||
<rect x="140" y="0" width="60" height="50" fill="#fee2e2" stroke="#ef4444" stroke-width="3" rx="3"/>
|
||||
<text x="170" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">c</text>
|
||||
|
||||
<rect x="210" y="0" width="60" height="50" fill="#fee2e2" stroke="#ef4444" stroke-width="4" rx="3"/>
|
||||
<text x="240" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">a</text>
|
||||
<polygon points="240,60 235,70 245,70" fill="#3498db"/>
|
||||
<text x="240" y="85" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#3498db" text-anchor="middle">R</text>
|
||||
|
||||
<text x="300" y="32" font-family="Arial, sans-serif" font-size="14" fill="#ef4444" font-weight="bold">Duplicate 'a'!</text>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- Transition -->
|
||||
<g transform="translate(400, 260)">
|
||||
<path d="M 0,0 L 0,30" stroke="#dee2e6" stroke-width="2" fill="none"/>
|
||||
<text x="10" y="20" font-family="Arial, sans-serif" font-size="14" font-style="italic" fill="#7f8c8d">Shrink from left</text>
|
||||
</g>
|
||||
|
||||
<!-- Step 2: Valid again -->
|
||||
<g transform="translate(150, 340)">
|
||||
<text x="0" y="-20" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="#2c3e50">2. Invariant restored</text>
|
||||
|
||||
<!-- Array -->
|
||||
<g transform="translate(0, 20)">
|
||||
<rect x="0" y="0" width="60" height="50" fill="#e5e7eb" stroke="#94a3b8" stroke-width="2" rx="3"/>
|
||||
<text x="30" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#94a3b8">a</text>
|
||||
|
||||
<rect x="70" y="0" width="60" height="50" fill="#d1fae5" stroke="#10b981" stroke-width="3" rx="3"/>
|
||||
<text x="100" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">b</text>
|
||||
<polygon points="100,60 95,70 105,70" fill="#27ae60"/>
|
||||
<text x="100" y="85" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#27ae60" text-anchor="middle">L</text>
|
||||
|
||||
<rect x="140" y="0" width="60" height="50" fill="#d1fae5" stroke="#10b981" stroke-width="3" rx="3"/>
|
||||
<text x="170" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">c</text>
|
||||
|
||||
<rect x="210" y="0" width="60" height="50" fill="#d1fae5" stroke="#10b981" stroke-width="3" rx="3"/>
|
||||
<text x="240" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">a</text>
|
||||
<polygon points="240,60 235,70 245,70" fill="#3498db"/>
|
||||
<text x="240" y="85" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#3498db" text-anchor="middle">R</text>
|
||||
|
||||
<text x="300" y="32" font-family="Arial, sans-serif" font-size="14" fill="#10b981" font-weight="bold">Valid again!</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
@@ -0,0 +1,54 @@
|
||||
<svg viewBox="0 0 800 450" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Background (REQUIRED) -->
|
||||
<rect width="800" height="450" fill="#f8f9fa" rx="10"/>
|
||||
|
||||
<!-- Title and Subtitle -->
|
||||
<text x="400" y="45" font-family="Arial, sans-serif" font-size="26" font-weight="bold" fill="#2c3e50" text-anchor="middle">Sliding Window: Frequency Tracking</text>
|
||||
<text x="400" y="75" font-family="Arial, sans-serif" font-size="16" fill="#7f8c8d" text-anchor="middle">Maintaining a character frequency map for the current window.</text>
|
||||
|
||||
<!-- Left: Window -->
|
||||
<g transform="translate(100, 150)">
|
||||
<text x="0" y="-30" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="#2c3e50">Current Window</text>
|
||||
|
||||
<!-- Array -->
|
||||
<g transform="translate(0, 20)">
|
||||
<rect x="0" y="0" width="60" height="50" fill="#d1fae5" stroke="#10b981" stroke-width="3" rx="3"/>
|
||||
<text x="30" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">a</text>
|
||||
<polygon points="30,60 25,70 35,70" fill="#27ae60"/>
|
||||
<text x="30" y="85" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#27ae60" text-anchor="middle">L</text>
|
||||
|
||||
<rect x="70" y="0" width="60" height="50" fill="#d1fae5" stroke="#10b981" stroke-width="3" rx="3"/>
|
||||
<text x="100" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">b</text>
|
||||
|
||||
<rect x="140" y="0" width="60" height="50" fill="#d1fae5" stroke="#10b981" stroke-width="3" rx="3"/>
|
||||
<text x="170" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">a</text>
|
||||
<polygon points="170,60 165,70 175,70" fill="#3498db"/>
|
||||
<text x="170" y="85" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#3498db" text-anchor="middle">R</text>
|
||||
|
||||
<rect x="210" y="0" width="60" height="50" fill="#ffffff" stroke="#dee2e6" stroke-width="2" rx="3"/>
|
||||
<text x="240" y="32" font-family="monospace" font-size="22" text-anchor="middle" fill="#2c3e50">c</text>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- Right: Frequency Map -->
|
||||
<g transform="translate(500, 150)">
|
||||
<text x="0" y="-30" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="#2c3e50">Frequency Map</text>
|
||||
|
||||
<!-- Map Container -->
|
||||
<rect x="0" y="0" width="150" height="120" fill="#ffffff" stroke="#dee2e6" stroke-width="2" rx="8"/>
|
||||
|
||||
<!-- Entries -->
|
||||
<g transform="translate(25, 35)">
|
||||
<text x="0" y="0" font-family="monospace" font-size="18" fill="#2c3e50">'a' : 2</text>
|
||||
<text x="0" y="30" font-family="monospace" font-size="18" fill="#2c3e50">'b' : 1</text>
|
||||
<text x="0" y="60" font-family="monospace" font-size="18" fill="#7f8c8d">'c' : 0</text>
|
||||
</g>
|
||||
|
||||
<!-- Invariant label -->
|
||||
<rect x="-20" y="140" width="190" height="40" fill="#e3f2fd" stroke="#3498db" stroke-width="1" rx="5"/>
|
||||
<text x="75" y="165" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#1565c0" text-anchor="middle">INVARIANT: SYNCED STATE</text>
|
||||
</g>
|
||||
|
||||
<!-- Connector -->
|
||||
<path d="M 380,195 L 480,195" stroke="#dee2e6" stroke-width="2" stroke-dasharray="5,5" fill="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
Reference in New Issue
Block a user