docs(content): add new problem pages, improve binary‑search docs, fix image syntax, update appendix badge

This commit is contained in:
Prad Nukala committed 2026-10-01 16:40:47 -04:00
1 parent 978589b53e
commit 799dc2bb80
7 files changed
+420 -62

No files matched your search

@@ -0,0 +1,57 @@
---
title: '209. Minimum Size Subarray Sum'
description: Given an array of positive integers nums and a positive integer target, return the minimal length of a subarray whose sum is greater than or equal to target. If there is no such subarray, return 0 instead
icon: dot
topics:
- { name: "Array", slug: "array" }
- { name: "Binary Search", slug: "binary-search" }
- { name: "Sliding Window", slug: "sliding-window" }
- { name: "Prefix Sum", slug: "prefix-sum" }
issue: "https://github.com/prdlk/leetcode/issues/54"
sidebar:
label: 'Minimum Size Subarray Sum'
badge: 'Medium'
---
::::warning
If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log(n)).
::::
### Example 1:
- Input: `target = 7, nums = [2,3,1,2,4,3]`
- Output: `2`
- Explanation: The subarray `[4,3]` has the minimal length under the problem constraint.
### Example 2:
- Input: `target = 4, nums = [1,4,4]`
- Output: `1`
### Example 3:
- Input: `target = 11, nums = [1,1,1,1,1,1,1,1]`
- Output: `0`
### Constraints:
- `1 <= target <= 10^9`
- `1 <= nums.length <= 10^5`
- `1 <= nums[i] <= 10^4`
## Solution
```py
class Solution:
def minSubArrayLen(self, target: int, nums: list[int]) -> int:
window_sum = 0
length = len(nums) + 1
left = 0
for right in range(len(nums)):
window_sum += nums[right]
while window_sum >= target:
length = min(length, right - left + 1)
window_sum -= nums[left]
left += 1
if length > len(nums):
return 0
return length
```
@@ -4,12 +4,6 @@ description: 'Sliding window is a specialized two-pointer family where the point
hidden: true
---
:::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:
@@ -18,59 +12,130 @@ A problem belongs to this family when:
- 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?
:::tip
The rule for all three: every element enters once and leaves once, so the whole thing runs in O(n).
:::
<Accordion>
<AccordionItem title="What is an invariant?">
An invariant is a statement that stays true before and after every iteration. In a sliding window, that statement usually describes the window itself, such as “the window is valid,” “it has no duplicates,” or “its sum is at most the target.” It can also describe a helper structure, such as “the frequency map matches the characters currently inside the window.”
</AccordionItem>
<AccordionItem title="Why invariants matter?">
Without an invariant, shrinking the window is just a guess. You no longer know when the window is valid, when to update the answer, or why the left pointer should stop. The invariant is what makes the algorithm correct.
</AccordionItem>
<AccordionItem title="How sliding window differs from other two-pointer families?">
Sliding window is not the same as every other two-pointer pattern. In Container With Most Water, the interval is only the remaining search space. In sliding window, the interval itself is the thing you care about. In Remove Duplicates, the left side is already the finished answer prefix. In sliding window, both pointers describe a live window that is still being checked.
</AccordionItem>
</Accordion>
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
## 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.
:::
<Frame caption="Sliding Window Fixed Size" hint="">
<img src="../../../public/sliding-window-fixed-size.svg" alt="Sliding Window Fixed Size" />
<Frame caption="Sliding Window Fixed" hint="">
![](../../../public/sliding-window-fixed-size.svg)
</Frame>
### 2. Flexible-size windows with a validity rule
```python
def fixed_window(nums, k):
window_sum = 0
best = float('-inf')
for right in range(len(nums)):
window_sum += nums[right] # add the new element
if right >= k - 1: # window is full
best = max(best, window_sum) # record answer
window_sum -= nums[right - k + 1] # remove the oldest element
return best
```
<Steps>
<Step title="">
Add `nums[right]` to the window.
</Step>
<Step title="">
If the window has `k` elements, record the answer.
</Step>
<Step title="">
Remove the leftmost element so the window stays at size `k`.
</Step>
</Steps>
## 2. Flexible-size windows with a validity rule
:::tip
Here the window expands until invalid, then shrinks until valid again.
:::
<Frame caption="Sliding Window Flexible" hint="">
<img src="../../../public/sliding-window-flexible.svg" alt="Sliding Window Flexible" />
![](../../../public/sliding-window-flexible.svg)
</Frame>
### 3. Frequency-tracking windows
```python
def flexible_window(nums, target):
left = 0
window_sum = 0
best = 0
for right in range(len(nums)):
window_sum += nums[right] # grow the window
while window_sum > target: # window is invalid
window_sum -= nums[left] # shrink from the left
left += 1
best = max(best, right - left + 1) # window is valid, record answer
return best
```
<Steps>
<Step title="">
Add `nums[right]` to the window.
</Step>
<Step title="">
While the window is invalid, remove `nums[left]` and move `left` up.
</Step>
<Step title="">
The window is now valid. Record its size.
</Step>
</Steps>
---
For "shortest window" problems, swap the logic: use `while` for the *valid* case, record the answer inside the loop, then shrink.
```python
def shortest_valid_window(nums, target):
left = 0
window_sum = 0
best = float('inf')
for right in range(len(nums)):
window_sum += nums[right]
while window_sum >= target: # window is valid
best = min(best, right - left + 1) # record, then try to shrink
window_sum -= nums[left]
left += 1
return best if best != float('inf') else 0
```
## 3. Frequency-tracking windows
:::tip
The difficulty comes from keeping the bookkeeping correct as characters enter and leave.
@@ -78,34 +143,73 @@ The difficulty comes from keeping the bookkeeping correct as characters enter an
<Frame caption="Frequency-tracking windows" hint="">
<img src="../../../public/sliding-window-frequency.svg" alt="Frequency-tracking windows" />
![](../../../public/sliding-window-frequency.svg)
</Frame>
## How Sliding Window Differs From Other Two-Pointer Families
```python
from collections import defaultdict
Compare it with Container With Most Water:
def frequency_window(s):
left = 0
counts = defaultdict(int)
best = 0
- In sliding window, the interval itself has meaning.
- In container, the interval is just the remaining search space.
for right in range(len(s)):
counts[s[right]] += 1 # character enters
Compare it with Remove Duplicates:
while counts[s[right]] > 1: # rule: no repeats
counts[s[left]] -= 1 # character leaves
left += 1
- In sliding window, both pointers describe a live window.
- In compaction, the left part of the array is already the answer prefix.
best = max(best, right - left + 1)
## A Practical Template
return best
```
A common variable-size sliding window has this shape:
<Steps>
<Step title="">
Add `s[right]` to the window.
</Step>
<Step title="">
While the window has more than one character, remove `s[left]` and move `left` up.
</Step>
<Step title="">
The window is now valid. Record its size.
</Step>
</Steps>
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.
For anagram or "minimum window substring" problems, you also keep a target count. Track how many characters currently match the target with one integer (`matched`). Update it only when a count crosses the target value. This keeps each step `O(1)`.
As you work through this section, keep asking:
```python
def anagram_window(s, p):
need = defaultdict(int)
for c in p:
need[c] += 1
counts = defaultdict(int)
matched = 0 # how many chars have counts[c] == need[c]
result = []
k = len(p)
for right in range(len(s)):
c = s[right]
counts[c] += 1
if counts[c] == need[c]:
matched += 1
if right >= k: # window too big, remove left
d = s[right - k]
if counts[d] == need[d]:
matched -= 1
counts[d] -= 1
if matched == len(need):
result.append(right - k + 1)
return result
```
:::warning
What invariant does my window maintain, and at what moment is it safe to update the answer?
:::