mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 13:12:44 +00:00
feat: migrate docs
This commit is contained in:
1 parent
e64285f201
commit
9fbe800fed
81 files changed
+30
-8255
No files matched your search
@@ -1,118 +0,0 @@
|
||||
---
|
||||
title: 'Frequency Map'
|
||||
description: 'Converging/parallel index walk that prunes the O(n^2) pair space using order.'
|
||||
---
|
||||
|
||||
## The idea
|
||||
|
||||
A frequency map is a hash table with one job: **count things**.
|
||||
|
||||
Key = the thing. Value = how many times you saw it.
|
||||
One pass to build. O(1) to ask "how many?"
|
||||
|
||||
Most string and array problems fall to this question:
|
||||
"Do these two collections contain the same stuff?"
|
||||
Count both. Compare the counts.
|
||||
|
||||
## The picture
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
S["'banana'"] --> C["Counter"]
|
||||
C --> B["b → 1"]
|
||||
C --> A["a → 3"]
|
||||
C --> N["n → 2"]
|
||||
|
||||
style C fill:#1565c0,color:#fff
|
||||
```
|
||||
|
||||
## The Python tool
|
||||
|
||||
`Counter` builds the map in one line. `defaultdict(int)` when you need to count by hand.
|
||||
|
||||
```python
|
||||
from collections import Counter, defaultdict
|
||||
|
||||
count = Counter("banana") # {'a': 3, 'n': 2, 'b': 1}
|
||||
count.most_common(2) # [('a', 3), ('n', 2)]
|
||||
|
||||
freq = defaultdict(int)
|
||||
for c in "banana":
|
||||
freq[c] += 1 # no KeyError, starts at 0
|
||||
```
|
||||
|
||||
## Ransom Note (LC 383) — do I have enough letters?
|
||||
|
||||
Count the magazine. Spend letters as the note needs them.
|
||||
Counter subtraction does this in two lines.
|
||||
|
||||
```python
|
||||
from collections import Counter
|
||||
|
||||
def can_construct(ransom_note: str, magazine: str) -> bool:
|
||||
need = Counter(ransom_note)
|
||||
have = Counter(magazine)
|
||||
return all(have[c] >= n for c, n in need.items())
|
||||
```
|
||||
|
||||
## Top K Frequent (LC 347) — count, then rank
|
||||
|
||||
Two steps: count everything, then pick the k biggest counts.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["nums:<br/>1 1 1 2 2 3"] --> B["Count:<br/>1→3, 2→2, 3→1"]
|
||||
B --> C["Buckets by count:<br/>slot 3: [1]<br/>slot 2: [2]<br/>slot 1: [3]"]
|
||||
C --> D["Walk from top:<br/>[1, 2] ✓"]
|
||||
|
||||
style D fill:#2e7d32,color:#fff
|
||||
```
|
||||
|
||||
Bucket sort trick: a number can appear at most n times.
|
||||
So make n+1 buckets. Put each number in the bucket of its count.
|
||||
Walk buckets from the top. O(n) — no sort, no heap.
|
||||
|
||||
```python
|
||||
from collections import Counter
|
||||
|
||||
def top_k_frequent(nums: list[int], k: int) -> list[int]:
|
||||
count = Counter(nums)
|
||||
buckets = [[] for _ in range(len(nums) + 1)]
|
||||
for num, freq in count.items():
|
||||
buckets[freq].append(num)
|
||||
|
||||
result = []
|
||||
for freq in range(len(buckets) - 1, 0, -1):
|
||||
for num in buckets[freq]:
|
||||
result.append(num)
|
||||
if len(result) == k:
|
||||
return result
|
||||
```
|
||||
|
||||
## Say the trade-off out loud
|
||||
|
||||
Three ways to rank counts. Name them in the interview:
|
||||
|
||||
| Method | Time | When |
|
||||
|---|---|---|
|
||||
| Sort the counts | O(n log n) | Fine, simple |
|
||||
| Heap of size k | O(n log k) | k small, streaming |
|
||||
| Bucket sort | O(n) | Best — counts are bounded by n |
|
||||
|
||||
## Complexity
|
||||
|
||||
| | Time | Space |
|
||||
|---|---|---|
|
||||
| Build the map | O(n) | O(u) — unique items |
|
||||
| Lookup | O(1) | — |
|
||||
|
||||
## Close-out ritual
|
||||
|
||||
Before you submit, say out loud:
|
||||
1. Time and space complexity.
|
||||
2. One edge case trace: empty string, k = number of unique items, or one element repeated n times.
|
||||
|
||||
## Plan problems
|
||||
|
||||
**A-set:** LC 217 · 242 · 1 · 49 · 347
|
||||
**B-set:** LC 383 · 205 · 128 · 290
|
||||
@@ -1,116 +0,0 @@
|
||||
---
|
||||
title: 'Two Pointers'
|
||||
description: 'Converging/parallel index walk that prunes the O(n^2) pair space using order.'
|
||||
---
|
||||
|
||||
## The idea
|
||||
|
||||
Checking every pair costs O(n²). That is n² boxes to open.
|
||||
|
||||
But if the array is **ordered**, you do not need every pair.
|
||||
Put one pointer at each end. Look at the sum:
|
||||
- Too small? Only a bigger left value can help. Move left in.
|
||||
- Too big? Only a smaller right value can help. Move right in.
|
||||
|
||||
Each move kills a whole row of the pair space. O(n²) → O(n).
|
||||
|
||||
## The picture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["2 7 11 15 target 18<br/>L R"] --> B["2 + 15 = 17 < 18<br/>too small → move L right"]
|
||||
B --> C["2 7 11 15<br/> L R"]
|
||||
C --> D["7 + 15 = 22 > 18<br/>too big → move R left"]
|
||||
D --> E["2 7 11 15<br/> L R"]
|
||||
E --> F["7 + 11 = 18 ✓"]
|
||||
|
||||
style F fill:#2e7d32,color:#fff
|
||||
```
|
||||
|
||||
## Not the same as binary search
|
||||
|
||||
Binary search **jumps** to the middle and discards half unseen — O(log n).
|
||||
Two pointers **walks** — every element gets inspected once — O(n).
|
||||
Both need order. Different moves.
|
||||
|
||||
## Two Sum II (LC 167) — the pure template
|
||||
|
||||
```python
|
||||
def two_sum(numbers: list[int], target: int) -> list[int]:
|
||||
lo, hi = 0, len(numbers) - 1
|
||||
|
||||
while lo < hi:
|
||||
total = numbers[lo] + numbers[hi]
|
||||
if total == target:
|
||||
return [lo + 1, hi + 1]
|
||||
if total < target:
|
||||
lo += 1 # only a bigger value helps
|
||||
else:
|
||||
hi -= 1 # only a smaller value helps
|
||||
```
|
||||
|
||||
## Container With Most Water (LC 11) — move the shorter wall
|
||||
|
||||
Water = width × shorter wall.
|
||||
Moving the taller wall can never help — width shrinks, height cannot grow.
|
||||
So always move the shorter one. Say this proof in the interview.
|
||||
|
||||
```python
|
||||
def max_area(height: list[int]) -> int:
|
||||
lo, hi = 0, len(height) - 1
|
||||
best = 0
|
||||
|
||||
while lo < hi:
|
||||
best = max(best, (hi - lo) * min(height[lo], height[hi]))
|
||||
if height[lo] < height[hi]:
|
||||
lo += 1
|
||||
else:
|
||||
hi -= 1
|
||||
return best
|
||||
```
|
||||
|
||||
## 3Sum (LC 15) — fix one, converge two
|
||||
|
||||
Sort first. Fix the smallest number. Now it is Two Sum II on the rest.
|
||||
Skip duplicates at every level or you get repeat triplets.
|
||||
|
||||
```python
|
||||
def three_sum(nums: list[int]) -> list[list[int]]:
|
||||
nums.sort()
|
||||
result = []
|
||||
|
||||
for i in range(len(nums) - 2):
|
||||
if i > 0 and nums[i] == nums[i - 1]:
|
||||
continue # skip duplicate anchor
|
||||
lo, hi = i + 1, len(nums) - 1
|
||||
while lo < hi:
|
||||
total = nums[i] + nums[lo] + nums[hi]
|
||||
if total < 0:
|
||||
lo += 1
|
||||
elif total > 0:
|
||||
hi -= 1
|
||||
else:
|
||||
result.append([nums[i], nums[lo], nums[hi]])
|
||||
lo += 1
|
||||
while lo < hi and nums[lo] == nums[lo - 1]:
|
||||
lo += 1 # skip duplicate pair
|
||||
return result
|
||||
```
|
||||
|
||||
## Complexity
|
||||
|
||||
| | Time | Space |
|
||||
|---|---|---|
|
||||
| Converging pair | O(n) | O(1) |
|
||||
| 3Sum | O(n²) — sort + n passes | O(1) extra |
|
||||
|
||||
## Close-out ritual
|
||||
|
||||
Before you submit, say out loud:
|
||||
1. Time and space complexity.
|
||||
2. One edge case trace: two elements, all duplicates, or no valid answer.
|
||||
|
||||
## Plan problems
|
||||
|
||||
**A-set:** LC 125 · 167 · 15 · 11 · 42
|
||||
**B-set:** LC 392 · 977 · 189 · 80
|
||||
@@ -1,119 +0,0 @@
|
||||
---
|
||||
title: 'Prefix Sum'
|
||||
description: 'Precomputed cumulative state for O(1) range queries.'
|
||||
---
|
||||
|
||||
## The idea
|
||||
|
||||
Precompute running totals once. Then any range sum costs O(1).
|
||||
|
||||
Like mile markers on a highway.
|
||||
Distance from mile 30 to mile 80? Subtract: 80 − 30 = 50.
|
||||
You do not re-drive the road.
|
||||
|
||||
**The formula:** `sum(i..j) = prefix[j + 1] - prefix[i]`
|
||||
|
||||
## The picture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["nums: 3 1 4 1 5"] --> B["prefix: 0 3 4 8 9 14"]
|
||||
B --> C["sum(1..3) = prefix[4] − prefix[1]<br/>= 9 − 3 = 6"]
|
||||
C --> D["Check: 1 + 4 + 1 = 6 ✓"]
|
||||
|
||||
style D fill:#2e7d32,color:#fff
|
||||
```
|
||||
|
||||
The leading 0 matters. It makes ranges that start at index 0 work with no special case.
|
||||
|
||||
## Range Sum Query (LC 303)
|
||||
|
||||
Pay O(n) once at build time. Answer every query in O(1).
|
||||
|
||||
```python
|
||||
from itertools import accumulate
|
||||
|
||||
class NumArray:
|
||||
def __init__(self, nums: list[int]):
|
||||
self.prefix = [0] + list(accumulate(nums))
|
||||
|
||||
def sum_range(self, left: int, right: int) -> int:
|
||||
return self.prefix[right + 1] - self.prefix[left]
|
||||
```
|
||||
|
||||
## Prefix + Hashmap (LC 560 — Subarray Sum Equals K)
|
||||
|
||||
The signature trick of this topic. The question flips:
|
||||
"Which subarrays sum to k?" becomes
|
||||
"At each point, how many *earlier* prefixes equal `current − k`?"
|
||||
|
||||
Because: if `prefix[j] − prefix[i] = k`, the slice between them sums to k.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["Walk the array,<br/>carry running sum"] --> B["Ask the map:<br/>seen sum − k before?"]
|
||||
B --> C["Yes, m times →<br/>add m to answer"]
|
||||
B --> D["Record current sum<br/>in the map"]
|
||||
D --> A
|
||||
|
||||
style C fill:#2e7d32,color:#fff
|
||||
```
|
||||
|
||||
```python
|
||||
from collections import defaultdict
|
||||
|
||||
def subarray_sum(nums: list[int], k: int) -> int:
|
||||
count = 0
|
||||
current = 0
|
||||
seen = defaultdict(int)
|
||||
seen[0] = 1 # empty prefix — subarrays that start at 0
|
||||
|
||||
for n in nums:
|
||||
current += n
|
||||
count += seen[current - k] # ask first
|
||||
seen[current] += 1 # record after
|
||||
return count
|
||||
```
|
||||
|
||||
**Order matters.** Ask before you record, or a subarray of length 0 counts itself when k = 0.
|
||||
|
||||
## Product variant (LC 238 — Product of Array Except Self)
|
||||
|
||||
Same idea, two directions. Prefix products from the left, suffix products from the right.
|
||||
`answer[i] = left[i] × right[i]` — everything except i.
|
||||
|
||||
```python
|
||||
def product_except_self(nums: list[int]) -> list[int]:
|
||||
n = len(nums)
|
||||
result = [1] * n
|
||||
|
||||
left = 1
|
||||
for i in range(n):
|
||||
result[i] = left
|
||||
left *= nums[i]
|
||||
|
||||
right = 1
|
||||
for i in range(n - 1, -1, -1):
|
||||
result[i] *= right
|
||||
right *= nums[i]
|
||||
return result
|
||||
```
|
||||
|
||||
## Complexity
|
||||
|
||||
| | Time | Space |
|
||||
|---|---|---|
|
||||
| Build | O(n) | O(n) |
|
||||
| Each range query | O(1) | — |
|
||||
| Prefix + hashmap | O(n) one pass | O(n) |
|
||||
|
||||
## Close-out ritual
|
||||
|
||||
Before you submit, say out loud:
|
||||
1. Time and space complexity.
|
||||
2. One edge case trace: range starting at 0, k = 0 with zeros in the array, or negative numbers (this is why sliding window fails and prefix + hashmap wins).
|
||||
|
||||
## Plan problems
|
||||
|
||||
**A-set:** LC 303 · 238 · 560
|
||||
**B-set:** LC 525 · 974
|
||||
@@ -1,117 +0,0 @@
|
||||
---
|
||||
title: 'Sliding Window'
|
||||
description: 'Two pointers plus incremental state between them.'
|
||||
---
|
||||
|
||||
## The idea
|
||||
|
||||
Two pointers that move the **same direction**, carrying state between them.
|
||||
|
||||
Think of a caterpillar:
|
||||
- The head crawls forward and eats (expand right).
|
||||
- When the rule breaks, the tail pulls in until the rule holds again (contract left).
|
||||
|
||||
The window is always a **contiguous** slice. You never rebuild it — you update the carried state as edges move. That is what makes it O(n).
|
||||
|
||||
**The recipe:**
|
||||
1. Expand right. Add the new element to your state.
|
||||
2. Rule broken? Contract left until it holds.
|
||||
3. Record the best window. Repeat.
|
||||
|
||||
## The picture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["a b c a b c<br/>[a] window = a"] --> B["[a b] expand → ab"]
|
||||
B --> C["[a b c] expand → abc, best = 3"]
|
||||
C --> D["a [b c a] 'a' repeats → contract, then expand"]
|
||||
D --> E["a b [c a b] keep sliding, best stays 3"]
|
||||
|
||||
style C fill:#2e7d32,color:#fff
|
||||
```
|
||||
|
||||
## Longest Substring Without Repeating (LC 3)
|
||||
|
||||
State = a set of chars in the window. Repeat found? Shrink from the left until it is gone.
|
||||
|
||||
```python
|
||||
def length_of_longest_substring(s: str) -> int:
|
||||
window = set()
|
||||
left = 0
|
||||
best = 0
|
||||
|
||||
for right, c in enumerate(s):
|
||||
while c in window: # rule broken
|
||||
window.remove(s[left]) # contract left
|
||||
left += 1
|
||||
window.add(c) # expand right
|
||||
best = max(best, right - left + 1)
|
||||
return best
|
||||
```
|
||||
|
||||
## Best Time to Buy and Sell (LC 121) — the hidden window
|
||||
|
||||
Looks like a stock problem. It is a window problem.
|
||||
Left = cheapest buy so far. Right = today. Carry one number: the min price.
|
||||
|
||||
```python
|
||||
def max_profit(prices: list[int]) -> int:
|
||||
min_price = prices[0]
|
||||
best = 0
|
||||
|
||||
for p in prices[1:]:
|
||||
best = max(best, p - min_price)
|
||||
min_price = min(min_price, p)
|
||||
return best
|
||||
```
|
||||
|
||||
## Character Replacement (LC 424) — window with a budget
|
||||
|
||||
Rule: window is valid if `window size − count of top letter ≤ k`.
|
||||
That many replacements fix the window. Carry a frequency map.
|
||||
|
||||
```python
|
||||
from collections import defaultdict
|
||||
|
||||
def character_replacement(s: str, k: int) -> int:
|
||||
count = defaultdict(int)
|
||||
left = 0
|
||||
best = 0
|
||||
top = 0 # highest letter count seen
|
||||
|
||||
for right, c in enumerate(s):
|
||||
count[c] += 1
|
||||
top = max(top, count[c])
|
||||
if (right - left + 1) - top > k: # over budget
|
||||
count[s[left]] -= 1 # contract exactly one step
|
||||
left += 1
|
||||
best = max(best, right - left + 1)
|
||||
return best
|
||||
```
|
||||
|
||||
## When the window fails
|
||||
|
||||
Sliding window needs a one-way rule: **growing can only hurt, shrinking can only help.**
|
||||
Negative numbers break this — a bigger window can flip from bad to good.
|
||||
That is when you reach for prefix sum + hashmap (LC 560) instead.
|
||||
Say this decision out loud in the interview.
|
||||
|
||||
## Complexity
|
||||
|
||||
| | Time | Space |
|
||||
|---|---|---|
|
||||
| All patterns above | O(n) — each index enters and leaves once | O(1) or O(alphabet) |
|
||||
|
||||
## Close-out ritual
|
||||
|
||||
Before you submit, say out loud:
|
||||
1. Time and space complexity — note each element enters and leaves the window at most once.
|
||||
2. One edge case trace: empty string, all same char, or k larger than the string.
|
||||
|
||||
## Plan problems
|
||||
|
||||
**A-set:** LC 121 · 3 · 424 · 567 · 76
|
||||
**B-set:** LC 209 · 1004 · 643
|
||||
|
||||
<YouTube id="QGNAVBn1_bc" title="Sliding Window" />
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
---
|
||||
title: 'Binary Search'
|
||||
description: 'In algorithms, arrays and strings are very similar. They are both ordered collections of elements. The difference is that arrays are mutable, while strings are immutable.'
|
||||
---
|
||||
|
||||
## The idea
|
||||
|
||||
You look for a name in a phone book. You do not start at page 1.
|
||||
You open the middle. Too far? Go left. Not far enough? Go right.
|
||||
Each step throws away half the book.
|
||||
|
||||
100 items → 7 steps. 4 billion items → 32 steps.
|
||||
|
||||
**The core rule:** ask a yes/no question that flips exactly once.
|
||||
Everything left of the flip is "no". Everything right is "yes".
|
||||
Binary search finds the flip point.
|
||||
|
||||
## The picture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["Array: 1 3 5 7 9 11 13<br/>Target: 9"] --> B["mid = 7<br/>7 < 9 → discard left half"]
|
||||
B --> C["Array: 9 11 13<br/>mid = 11<br/>11 > 9 → discard right half"]
|
||||
C --> D["Array: 9<br/>mid = 9<br/>Found ✓"]
|
||||
|
||||
style D fill:#2e7d32,color:#fff
|
||||
```
|
||||
|
||||
## The template
|
||||
|
||||
```python
|
||||
def binary_search(nums: list[int], target: int) -> int:
|
||||
lo, hi = 0, len(nums) - 1
|
||||
|
||||
while lo <= hi:
|
||||
mid = (lo + hi) // 2
|
||||
if nums[mid] == target:
|
||||
return mid
|
||||
if nums[mid] < target:
|
||||
lo = mid + 1
|
||||
else:
|
||||
hi = mid - 1
|
||||
return -1
|
||||
```
|
||||
|
||||
## Search the answer space (LC 875 — Koko Eating Bananas)
|
||||
|
||||
The array does not need to exist. You can binary search over *possible answers*.
|
||||
Ask: "does speed k work?" Slow speeds fail. Fast speeds work.
|
||||
The answer flips once. Find the flip.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["k=1<br/>NO"] --> B["k=2<br/>NO"] --> C["k=3<br/>NO"] --> D["k=4<br/>YES ← answer"] --> E["k=5<br/>YES"] --> F["k=6<br/>YES"]
|
||||
|
||||
style D fill:#2e7d32,color:#fff
|
||||
```
|
||||
|
||||
```python
|
||||
import math
|
||||
|
||||
def min_eating_speed(piles: list[int], h: int) -> int:
|
||||
def k_works(k: int) -> bool:
|
||||
return sum(math.ceil(p / k) for p in piles) <= h
|
||||
|
||||
lo, hi = 1, max(piles)
|
||||
|
||||
while lo < hi:
|
||||
mid = (lo + hi) // 2
|
||||
if k_works(mid):
|
||||
hi = mid # mid works — keep it, look left
|
||||
else:
|
||||
lo = mid + 1 # mid fails — discard it
|
||||
return lo
|
||||
```
|
||||
|
||||
## Not the same as two pointers
|
||||
|
||||
Two pointers **walks** — it inspects every element it passes. O(n).
|
||||
Binary search **jumps** — it inspects one midpoint and discards half unseen. O(log n).
|
||||
|
||||
## Complexity
|
||||
|
||||
| | Time | Space |
|
||||
|---|---|---|
|
||||
| Sorted array | O(log n) | O(1) |
|
||||
| Answer space | O(n log m) | O(1) |
|
||||
|
||||
n = array size, m = answer range.
|
||||
|
||||
## Close-out ritual
|
||||
|
||||
Before you submit, say out loud:
|
||||
1. Time and space complexity.
|
||||
2. One edge case trace: empty array, one element, or target not present.
|
||||
|
||||
## Plan problems
|
||||
|
||||
**A-set:** LC 704 · 74 · 875 · 33 · 153
|
||||
**B-set:** LC 35 · 162 · 34 · 4 ⭐
|
||||
@@ -1,121 +0,0 @@
|
||||
---
|
||||
title: Breadth-First Search
|
||||
---
|
||||
|
||||
# Breadth-First Search (BFS)
|
||||
|
||||
## The idea
|
||||
|
||||
You want a mango seller. You ask your friends first.
|
||||
No luck? You ask friends-of-friends. Then their friends.
|
||||
You search in **rings**, closest first.
|
||||
|
||||
That is BFS. It answers two questions:
|
||||
1. **Is there a path** from A to B?
|
||||
2. **What is the shortest path?** (unweighted — fewest hops)
|
||||
|
||||
BFS is *always* shortest path on unweighted graphs. First time you reach a node = fewest possible steps.
|
||||
|
||||
## The picture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
YOU((You)) --> A((Alice))
|
||||
YOU --> B((Bob))
|
||||
A --> C((Claire))
|
||||
A --> D((Dan))
|
||||
B --> E((Eve))
|
||||
E --> M((Mango seller ✓))
|
||||
|
||||
style YOU fill:#1565c0,color:#fff
|
||||
style A fill:#6a1b9a,color:#fff
|
||||
style B fill:#6a1b9a,color:#fff
|
||||
style C fill:#ef6c00,color:#fff
|
||||
style D fill:#ef6c00,color:#fff
|
||||
style E fill:#ef6c00,color:#fff
|
||||
style M fill:#2e7d32,color:#fff
|
||||
```
|
||||
|
||||
Blue = start. Purple = ring 1. Orange = ring 2. Green = found at ring 3.
|
||||
|
||||
## The two tools
|
||||
|
||||
1. **Queue** — first in, first out. This keeps the rings in order.
|
||||
2. **Visited set** — never check the same node twice. Without it, cycles loop forever.
|
||||
|
||||
## The template
|
||||
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
def bfs(start, graph: dict) -> None:
|
||||
queue = deque([start])
|
||||
visited = {start}
|
||||
|
||||
while queue:
|
||||
level_size = len(queue) # snapshot = one full ring
|
||||
for _ in range(level_size):
|
||||
node = queue.popleft()
|
||||
# process node here
|
||||
for nxt in graph.get(node, []):
|
||||
if nxt not in visited:
|
||||
visited.add(nxt) # mark WHEN queued, not when popped
|
||||
queue.append(nxt)
|
||||
```
|
||||
|
||||
## Multi-source BFS (LC 994 — Rotting Oranges)
|
||||
|
||||
Start with *all* rotten oranges in the queue at once.
|
||||
Each ring = one minute of rot spreading.
|
||||
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
def oranges_rotting(grid: list[list[int]]) -> int:
|
||||
rows, cols = len(grid), len(grid[0])
|
||||
queue = deque()
|
||||
fresh = 0
|
||||
|
||||
for r in range(rows):
|
||||
for c in range(cols):
|
||||
if grid[r][c] == 2:
|
||||
queue.append((r, c))
|
||||
elif grid[r][c] == 1:
|
||||
fresh += 1
|
||||
|
||||
minutes = 0
|
||||
dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)]
|
||||
|
||||
while queue and fresh > 0:
|
||||
for _ in range(len(queue)):
|
||||
r, c = queue.popleft()
|
||||
for dr, dc in dirs:
|
||||
nr, nc = r + dr, c + dc
|
||||
if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == 1:
|
||||
grid[nr][nc] = 2
|
||||
fresh -= 1
|
||||
queue.append((nr, nc))
|
||||
minutes += 1
|
||||
|
||||
return minutes if fresh == 0 else -1
|
||||
```
|
||||
|
||||
## Complexity
|
||||
|
||||
| | Time | Space |
|
||||
|---|---|---|
|
||||
| BFS | O(V + E) | O(V) |
|
||||
|
||||
V = nodes, E = edges. On a grid: O(rows × cols).
|
||||
|
||||
## Close-out ritual
|
||||
|
||||
Before you submit, say out loud:
|
||||
1. Time and space complexity.
|
||||
2. One edge case trace: empty graph, start = target, or unreachable target.
|
||||
|
||||
## Plan problems
|
||||
|
||||
**Tree BFS A-set:** LC 102 · 199 · 1448
|
||||
**Graph BFS A-set:** LC 994 · 127
|
||||
**B-set:** LC 103 · 637 · 909 · 433 · 286
|
||||
@@ -1,110 +0,0 @@
|
||||
---
|
||||
title: Depth-First Search
|
||||
---
|
||||
|
||||
# Depth-First Search (DFS)
|
||||
|
||||
## The idea
|
||||
|
||||
BFS searches in rings. DFS picks one path and follows it to the end.
|
||||
Dead end? Back up one step. Try the next branch.
|
||||
|
||||
Like exploring a maze with one hand on the wall.
|
||||
|
||||
Use DFS when:
|
||||
- The answer **composes from subtrees** (depth, path sums, subtree checks).
|
||||
- You need **all** of a region (islands, flood fill, connected components).
|
||||
|
||||
Use BFS when you need **shortest path**. DFS does not give shortest path.
|
||||
|
||||
## The picture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A((1)) --> B((2))
|
||||
A --> C((5))
|
||||
B --> D((3))
|
||||
B --> E((4))
|
||||
C --> F((6))
|
||||
|
||||
style A fill:#1565c0,color:#fff
|
||||
style B fill:#1565c0,color:#fff
|
||||
style D fill:#1565c0,color:#fff
|
||||
```
|
||||
|
||||
Visit order: 1 → 2 → 3 (bottom!) → back up → 4 → back up → 5 → 6.
|
||||
Numbers show the order. DFS goes **deep before wide**.
|
||||
|
||||
## Tree DFS — answers flow up (LC 104 — Max Depth)
|
||||
|
||||
The pattern: ask each child a question. Combine the answers. Return up.
|
||||
|
||||
```python
|
||||
def max_depth(root) -> int:
|
||||
if root is None:
|
||||
return 0 # base case
|
||||
left = max_depth(root.left)
|
||||
right = max_depth(root.right)
|
||||
return 1 + max(left, right) # combine + return up
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart BT
|
||||
D["leaf returns 1"] --> B["returns 1 + max(1,1) = 2"]
|
||||
E["leaf returns 1"] --> B
|
||||
B --> A["root returns 1 + max(2,1) = 3"]
|
||||
C["leaf returns 1"] --> A
|
||||
|
||||
style A fill:#2e7d32,color:#fff
|
||||
```
|
||||
|
||||
## Graph DFS — add a visited set (LC 200 — Number of Islands)
|
||||
|
||||
Graphs have cycles. Trees do not.
|
||||
So graph DFS needs one new thing: **mark where you have been.**
|
||||
On a grid, sink the land as you visit it — the grid *is* the visited set.
|
||||
|
||||
```python
|
||||
def num_islands(grid: list[list[str]]) -> int:
|
||||
rows, cols = len(grid), len(grid[0])
|
||||
count = 0
|
||||
|
||||
def sink(r: int, c: int) -> None:
|
||||
if r < 0 or r >= rows or c < 0 or c >= cols:
|
||||
return
|
||||
if grid[r][c] != "1":
|
||||
return
|
||||
grid[r][c] = "0" # mark visited
|
||||
sink(r + 1, c)
|
||||
sink(r - 1, c)
|
||||
sink(r, c + 1)
|
||||
sink(r, c - 1)
|
||||
|
||||
for r in range(rows):
|
||||
for c in range(cols):
|
||||
if grid[r][c] == "1":
|
||||
count += 1
|
||||
sink(r, c) # eat the whole island
|
||||
return count
|
||||
```
|
||||
|
||||
## Complexity
|
||||
|
||||
| | Time | Space |
|
||||
|---|---|---|
|
||||
| Tree DFS | O(n) | O(h) — call stack, h = height |
|
||||
| Graph DFS | O(V + E) | O(V) |
|
||||
|
||||
Worst case h = n (a stick-shaped tree).
|
||||
|
||||
## Close-out ritual
|
||||
|
||||
Before you submit, say out loud:
|
||||
1. Time and space complexity — name the call stack.
|
||||
2. One edge case trace: null root, single node, or all-water grid.
|
||||
|
||||
## Plan problems
|
||||
|
||||
**Tree DFS A-set:** LC 226 · 104 · 100 · 572 · 236 · 124 ⭐
|
||||
**Graph DFS A-set:** LC 200 · 695 · 133 · 417 · 130
|
||||
**B-set:** LC 101 · 112 · 129 · 543 · 399 · 261
|
||||
@@ -1,127 +0,0 @@
|
||||
---
|
||||
title: Dynamic Programming (1-D)
|
||||
---
|
||||
|
||||
# Dynamic Programming (1-D)
|
||||
|
||||
## The idea
|
||||
|
||||
DP is backtracking with a memory.
|
||||
|
||||
Backtracking tries every path. Many paths repeat the same subproblem.
|
||||
DP solves each subproblem **once**, saves the answer, and reuses it.
|
||||
|
||||
Grokking's rule: break the big problem into small problems.
|
||||
Solve the small ones first. Build up.
|
||||
|
||||
**The two things you must find:**
|
||||
1. **The state** — what does `dp[i]` mean, in one sentence?
|
||||
2. **The recurrence** — how does `dp[i]` come from earlier answers?
|
||||
|
||||
## The picture — why memo matters (Climbing Stairs)
|
||||
|
||||
Without memo, `f(5)` computes `f(3)` twice and `f(2)` three times:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["f(5)"] --> B["f(4)"]
|
||||
A --> C["f(3)"]
|
||||
B --> D["f(3)"]
|
||||
B --> E["f(2)"]
|
||||
C --> F["f(2)"]
|
||||
C --> G["f(1)"]
|
||||
D --> H["f(2)"]
|
||||
D --> I["f(1)"]
|
||||
|
||||
style C fill:#c62828,color:#fff
|
||||
style D fill:#c62828,color:#fff
|
||||
style E fill:#ef6c00,color:#fff
|
||||
style F fill:#ef6c00,color:#fff
|
||||
style H fill:#ef6c00,color:#fff
|
||||
```
|
||||
|
||||
Red and orange = repeated work. Memo turns the tree into a straight line: O(2ⁿ) → O(n).
|
||||
|
||||
## Climbing Stairs (LC 70)
|
||||
|
||||
State: `dp[i]` = ways to reach step i.
|
||||
Recurrence: you arrive from one step below or two below.
|
||||
|
||||
```python
|
||||
def climb_stairs(n: int) -> int:
|
||||
if n <= 2:
|
||||
return n
|
||||
prev2, prev1 = 1, 2
|
||||
for _ in range(3, n + 1):
|
||||
prev2, prev1 = prev1, prev1 + prev2
|
||||
return prev1
|
||||
```
|
||||
|
||||
## House Robber (LC 198)
|
||||
|
||||
State: `dp[i]` = max loot using houses 0..i.
|
||||
Recurrence at each house: **rob it** (skip the neighbor) or **skip it**.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["House i"] --> B["Rob:<br/>nums[i] + dp[i-2]"]
|
||||
A --> C["Skip:<br/>dp[i-1]"]
|
||||
B --> D["dp[i] = max of both"]
|
||||
C --> D
|
||||
|
||||
style D fill:#2e7d32,color:#fff
|
||||
```
|
||||
|
||||
```python
|
||||
def rob(nums: list[int]) -> int:
|
||||
skip = take = 0
|
||||
for n in nums:
|
||||
skip, take = max(skip, take), skip + n # skip it / rob it
|
||||
return max(skip, take)
|
||||
```
|
||||
|
||||
## Coin Change (LC 322)
|
||||
|
||||
State: `dp[a]` = fewest coins to make amount a.
|
||||
Recurrence: try each coin, take the best.
|
||||
|
||||
```python
|
||||
import math
|
||||
|
||||
def coin_change(coins: list[int], amount: int) -> int:
|
||||
dp = [math.inf] * (amount + 1)
|
||||
dp[0] = 0
|
||||
for a in range(1, amount + 1):
|
||||
for c in coins:
|
||||
if c <= a:
|
||||
dp[a] = min(dp[a], dp[a - c] + 1)
|
||||
return dp[amount] if dp[amount] != math.inf else -1
|
||||
```
|
||||
|
||||
## The interview script
|
||||
|
||||
Say these four lines out loud, in order:
|
||||
1. "The brute force is backtracking — try everything."
|
||||
2. "Subproblems overlap, so I will memoize."
|
||||
3. "State: dp[i] means ___." (one sentence)
|
||||
4. "Recurrence: dp[i] = ___."
|
||||
|
||||
## Complexity
|
||||
|
||||
| | Time | Space |
|
||||
|---|---|---|
|
||||
| Climbing Stairs / House Robber | O(n) | O(1) with rolling vars |
|
||||
| Coin Change | O(amount × coins) | O(amount) |
|
||||
|
||||
## Close-out ritual
|
||||
|
||||
Before you submit, say out loud:
|
||||
1. Time and space complexity.
|
||||
2. One edge case trace: n = 0 or 1, empty array, or unreachable amount (return -1).
|
||||
|
||||
## Plan problems
|
||||
|
||||
**A-set:** LC 70 · 746 · 198 · 213 · 322 · 300
|
||||
**B-set:** LC 139 · 91 · 647
|
||||
|
||||
Note: DP matters only if Google or Databricks advance to later rounds. Your fintech targets skew toward simulation, hashmap, and heap.
|
||||
@@ -1,95 +0,0 @@
|
||||
---
|
||||
title: Greedy Algorithms
|
||||
---
|
||||
|
||||
# Greedy Algorithms
|
||||
|
||||
## The idea
|
||||
|
||||
At each step, take the best move *right now*. Never look back.
|
||||
|
||||
Grokking's example: the classroom problem.
|
||||
You want the most classes in one room. Which do you pick?
|
||||
**Always pick the class that ends first.** It leaves the most room for the rest.
|
||||
|
||||
Greedy works only when the local best is *provably* the global best.
|
||||
When it works, it beats DP — no memo table, no lookback, often O(n).
|
||||
|
||||
## The picture
|
||||
|
||||
```mermaid
|
||||
gantt
|
||||
dateFormat HH:mm
|
||||
axisFormat %H:%M
|
||||
section Pick ✓
|
||||
Art (ends first) :done, 09:00, 45m
|
||||
Math (ends next) :done, 10:00, 60m
|
||||
Music :done, 11:00, 60m
|
||||
section Skip ✗
|
||||
English (overlaps Art) :crit, 09:30, 60m
|
||||
CS (overlaps Math) :crit, 10:30, 60m
|
||||
```
|
||||
|
||||
Pick by earliest end time. Skip anything that overlaps a pick.
|
||||
|
||||
## Kadane's — DP squeezed to one variable (LC 53 — Maximum Subarray)
|
||||
|
||||
The greedy question at each element:
|
||||
"Do I extend the running sum, or start fresh here?"
|
||||
If the running sum is negative, it only hurts. Drop it.
|
||||
|
||||
```python
|
||||
def max_sub_array(nums: list[int]) -> int:
|
||||
best = current = nums[0]
|
||||
|
||||
for n in nums[1:]:
|
||||
current = max(n, current + n) # extend or restart
|
||||
best = max(best, current)
|
||||
return best
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["-2"] --> B["1<br/>restart"] --> C["-2<br/>extend"] --> D["4<br/>restart"] --> E["3<br/>extend"] --> F["5<br/>extend"] --> G["6<br/>extend ← best"]
|
||||
|
||||
style G fill:#2e7d32,color:#fff
|
||||
```
|
||||
|
||||
## Jump Game (LC 55) — track the farthest reach
|
||||
|
||||
One pass. Keep the farthest index you can touch.
|
||||
If your position ever passes the reach, you are stuck.
|
||||
|
||||
```python
|
||||
def can_jump(nums: list[int]) -> bool:
|
||||
reach = 0
|
||||
for i, n in enumerate(nums):
|
||||
if i > reach:
|
||||
return False # stuck
|
||||
reach = max(reach, i + n)
|
||||
return True
|
||||
```
|
||||
|
||||
## How to justify greedy in an interview
|
||||
|
||||
Use an **exchange argument**: "If an optimal answer made a different choice here, I could swap in my greedy choice without making it worse."
|
||||
Say this out loud. It is the difference between guessing and proving.
|
||||
|
||||
## Complexity
|
||||
|
||||
| | Time | Space |
|
||||
|---|---|---|
|
||||
| One-pass greedy (Kadane, Jump) | O(n) | O(1) |
|
||||
| Sort-then-commit (intervals) | O(n log n) | O(1) |
|
||||
|
||||
## Close-out ritual
|
||||
|
||||
Before you submit, say out loud:
|
||||
1. Time and space complexity.
|
||||
2. One edge case trace: all-negative array, single element, or zero at index 0.
|
||||
|
||||
## Plan problems
|
||||
|
||||
**A-set:** LC 53 · 55 · 45 · 134
|
||||
**B-set:** LC 122 · 918 · 763
|
||||
**Feeds into topic 24 (Intervals):** LC 57 · 56 · 435 · 253
|
||||
@@ -1,6 +0,0 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({
|
||||
title: "Algorithms",
|
||||
order: 2,
|
||||
});
|
||||
@@ -1,65 +0,0 @@
|
||||
---
|
||||
title: 'Arrays and Strings'
|
||||
description: 'In algorithms, arrays and strings are very similar. They are both ordered collections of elements. The difference is that arrays are mutable, while strings are immutable.'
|
||||
sidebar:
|
||||
label: Arrays & Strings
|
||||
---
|
||||
|
||||
|
||||
Technically, an array can't be resized. A dynamic array, or list, can be. In the context of algorithm problems, usually when people talk about arrays, they are referring to dynamic arrays. In this entire course, we will be talking about dynamic arrays/lists, but we will just use the word "array".
|
||||
|
||||
## Time Complexity
|
||||
|
||||
Arrays and strings are both ordered collections of elements. The difference is that arrays are mutable, while strings are immutable.
|
||||
|
||||
| Operation | Array/List | String(Immutable) |
|
||||
| --------- | ---------- | ----------------- |
|
||||
| Appending to end | *O(1) | O(n) |
|
||||
| Popping from end | O(1) | O(n) |
|
||||
| Insertion, not from end | O(n) | O(n) |
|
||||
| Deletion, not from end | O(n) | O(n) |
|
||||
| Modifying an element | O(1) | O(n) |
|
||||
| Random access | *O(1) | O(n) |
|
||||
| Checking if an element exists | O(1) | O(n) |
|
||||
|
||||
:::note[Clarification 1]
|
||||
Appending to the end of a list is amortized O(1) time complexity. This means that the time complexity of appending to the end of a list is the same as the time complexity of appending to the end of an array.
|
||||
:::
|
||||
|
||||
:::note[Clarification 2]
|
||||
Random access in this context means that you can access an element at any index in constant time.
|
||||
:::
|
||||
|
||||
## Patterns
|
||||
|
||||
<Columns cols={2}>
|
||||
<Column>
|
||||
<Tile
|
||||
title="Two Pointers"
|
||||
description="Ship your first page in minutes."
|
||||
href="/leetcode/two-pointers"
|
||||
>
|
||||
<Icon icon="rocket" size={28} />
|
||||
</Tile>
|
||||
</Column>
|
||||
<Column>
|
||||
<Tile
|
||||
title="Sliding Window"
|
||||
description="Ship your first page in minutes."
|
||||
href="/leetcode/sliding-window"
|
||||
>
|
||||
<Icon icon="rocket" size={28} />
|
||||
</Tile>
|
||||
</Column>
|
||||
<Column>
|
||||
<Tile
|
||||
title="Prefix Sum"
|
||||
description="Ship your first page in minutes."
|
||||
href="/leetcode/prefix-sum"
|
||||
>
|
||||
<Icon icon="rocket" size={28} />
|
||||
</Tile>
|
||||
</Column>
|
||||
</Columns>
|
||||
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
---
|
||||
title: 'Hash Tables'
|
||||
description: 'In algorithms, arrays and strings are very similar. They are both ordered collections of elements. The difference is that arrays are mutable, while strings are immutable.'
|
||||
---
|
||||
|
||||
## The idea
|
||||
|
||||
A hash table is like a helpful grocery clerk.
|
||||
You say "avocado". She tells you the price at once.
|
||||
She does not walk the aisles. She just *knows*.
|
||||
|
||||
How? A hash function turns your key into a slot number.
|
||||
Same key → same slot, every time. Lookup is O(1).
|
||||
|
||||
## The picture
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
K1["'apple'"] --> H["Hash<br/>function"]
|
||||
K2["'milk'"] --> H
|
||||
K3["'avocado'"] --> H
|
||||
H --> S0["Slot 0: milk → 1.49"]
|
||||
H --> S1["Slot 1: apple → 0.67"]
|
||||
H --> S2["Slot 2: avocado → 1.99"]
|
||||
|
||||
style H fill:#1565c0,color:#fff
|
||||
```
|
||||
|
||||
## Three jobs it does
|
||||
|
||||
1. **Membership** — "have I seen this before?"
|
||||
2. **Frequency** — "how many times?"
|
||||
3. **Mapping** — "what goes with this?"
|
||||
|
||||
## Membership (LC 217 — Contains Duplicate)
|
||||
|
||||
```python
|
||||
def contains_duplicate(nums: list[int]) -> bool:
|
||||
seen = set()
|
||||
for n in nums:
|
||||
if n in seen:
|
||||
return True
|
||||
seen.add(n)
|
||||
return False
|
||||
```
|
||||
|
||||
## Frequency (LC 242 — Valid Anagram)
|
||||
|
||||
```python
|
||||
from collections import Counter
|
||||
|
||||
def is_anagram(s: str, t: str) -> bool:
|
||||
if len(s) != len(t):
|
||||
return False
|
||||
return Counter(s) == Counter(t)
|
||||
```
|
||||
|
||||
## Key design (LC 49 — Group Anagrams)
|
||||
|
||||
Sometimes the trick is *what you use as the key*.
|
||||
"eat", "tea", "ate" all sort to "aet". Sorted string = group key.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["eat"] --> K["key: 'aet'"]
|
||||
B["tea"] --> K
|
||||
C["ate"] --> K
|
||||
K --> G["group: [eat, tea, ate]"]
|
||||
|
||||
style K fill:#1565c0,color:#fff
|
||||
```
|
||||
|
||||
```python
|
||||
from collections import defaultdict
|
||||
|
||||
def group_anagrams(strs: list[str]) -> list[list[str]]:
|
||||
groups = defaultdict(list)
|
||||
for s in strs:
|
||||
key = "".join(sorted(s))
|
||||
groups[key].append(s)
|
||||
return list(groups.values())
|
||||
```
|
||||
|
||||
## Complexity
|
||||
|
||||
| | Average | Worst |
|
||||
|---|---|---|
|
||||
| Lookup / insert / delete | O(1) | O(n) |
|
||||
|
||||
Worst case comes from collisions. Interviews treat it as O(1).
|
||||
|
||||
## Close-out ritual
|
||||
|
||||
Before you submit, say out loud:
|
||||
1. Time and space complexity.
|
||||
2. One edge case trace: empty input, all same element, or key collision on your key design.
|
||||
|
||||
## Plan problems
|
||||
|
||||
**A-set:** LC 217 · 242 · 1 · 49 · 347
|
||||
**B-set:** LC 383 · 205 · 128 · 290
|
||||
@@ -1,6 +0,0 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({
|
||||
title: "Data Structures",
|
||||
order: 1,
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
title: Introduction
|
||||
description: Welcome to your new Blume docs.
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||

|
||||
|
||||
Welcome to **Blume** — markdown-first docs powered by Astro and Vite.
|
||||
|
||||
Edit `docs/index.mdx` to get started, then run `blume dev`.
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
title: Progress
|
||||
description: Live SRS campaign dashboard — phases, ladder, review queue, gates, and recent attempts, fetched from the SRS Worker.
|
||||
---
|
||||
|
||||
Live view of the 56-day campaign. Everything below is fetched client-side
|
||||
from the SRS Worker, so it is always current — no rebuild required.
|
||||
|
||||
<ProgressDashboard />
|
||||
@@ -1,47 +0,0 @@
|
||||
---
|
||||
title: '1. Two Sum'
|
||||
description: You are given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target
|
||||
sidebar:
|
||||
label: 'Two Sum'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Hash Table</Badge>
|
||||
|
||||
::::warning
|
||||
Can you come up with an algorithm that is less than O(n^2) time complexity?
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [2,7,11,15], target = 9`
|
||||
- Output: `[0,1]`
|
||||
- Explanation: Because `nums[0] + nums[1]` == `9`, we return [0, 1].
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [3,2,4], target = 6`
|
||||
- Output: `[1,2]`
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [3,3], target = 6`
|
||||
- Output: `[0,1]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `2 <= nums.length <= 10^4`
|
||||
- `-10^9 <= nums[i] <= 10^9`
|
||||
- `-10^9 <= target <= 10^9`
|
||||
- Only one valid answer exists.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def twoSum(self, nums: List[int], target: int) -> List[int]:
|
||||
seen = {}
|
||||
for i, num in enumerate(nums):
|
||||
complement = target - num
|
||||
if complement in seen:
|
||||
return [seen[complement], i]
|
||||
seen[num] = i
|
||||
return []
|
||||
```
|
||||
@@ -1,48 +0,0 @@
|
||||
---
|
||||
title: '11. Container With Most Water'
|
||||
description: You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the i^th line are (i, 0) and (i, height[i])
|
||||
sidebar:
|
||||
label: 'Container With Most Water'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Two Pointers</Badge>
|
||||
|
||||
::::warning
|
||||
Notice that you may not slant the container.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `height = [1,8,6,2,5,4,8,3,7]`
|
||||
- Output: `49`
|
||||
- Explanation: The above vertical lines are represented by array `[1,8,6,2,5,4,8,3,7]`. In this case, the max area of water (blue section) the container can contain is `49`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `height = [1,1]`
|
||||
- Output: `1`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `n == height.length`
|
||||
- `2 <= n <= 10^5`
|
||||
- `0 <= height[i] <= 10^4`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def maxArea(self, height: List[int]) -> int: # noqa: F821
|
||||
res = 0
|
||||
left = 0
|
||||
right = len(height) - 1
|
||||
|
||||
while left < right:
|
||||
area = (right - left) * min(height[left], height[right])
|
||||
res = max(res, area)
|
||||
if height[left] < height[right]:
|
||||
left += 1
|
||||
else:
|
||||
right -= 1
|
||||
|
||||
return res
|
||||
```
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
title: '121. Best Time to Buy and Sell Stock'
|
||||
description: You are given an array prices where prices[i] is the price of a given stock on the i^th day
|
||||
sidebar:
|
||||
label: 'Best Time to Buy and Sell Stock'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Sliding Window</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `prices = [7,1,5,3,6,4]`
|
||||
- Output: `5`
|
||||
- Explanation: Buy on day `2` (price = `1`) and sell on day `5` (price = `6`), profit = `6-1 = 5`. Note that buying on day `2` and selling on day `1` is not allowed because you must buy before you sell.
|
||||
|
||||
### Example 2:
|
||||
- Input: `prices = [7,6,4,3,1]`
|
||||
- Output: `0`
|
||||
- Explanation: In this case, no transactions are done and the max profit = `0`.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= prices.length <= 10^5`
|
||||
- `0 <= prices[i] <= 10^4`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def maxProfit(self, prices: List[int]) -> int:
|
||||
left = min(prices)
|
||||
for right in range(len(prices)):
|
||||
while curr > left:
|
||||
curr -= prices[left]
|
||||
left += 1
|
||||
ans = max(ans, curr)
|
||||
return ans
|
||||
```
|
||||
@@ -1,63 +0,0 @@
|
||||
---
|
||||
title: '1365. How Many Numbers Are Smaller Than the Current Number'
|
||||
description: Given the array nums, for each nums[i] find out how many numbers in the array are smaller than it. That is, for each nums[i] you have to count the number of valid j's such that j != i and nums[j] < nums[i]
|
||||
sidebar:
|
||||
label: 'How Many Numbers Are Smaller Than the Current Number'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Array</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [8,1,2,2,3]`
|
||||
- Output: `[4,0,1,1,3]`
|
||||
- Explanation: For `nums[0]=8` there exist four smaller numbers than it (`1`, `2`, `2` and `3`). For `nums[1]=1` does not exist any smaller number than it. For `nums[2]=2` there exist one smaller number than it (`1`). For `nums[3]=2` there exist one smaller number than it (`1`). For `nums[4]=3` there exist three smaller numbers than it (`1`, `2` and `2`).
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [6,5,4,8]`
|
||||
- Output: `[2,1,0,3]`
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [7,7,7,7]`
|
||||
- Output: `[0,0,0,0]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `2 <= nums.length <= 500`
|
||||
- `0 <= nums[i] <= 100`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @return {number[]}
|
||||
*/
|
||||
|
||||
var smallerNumbersThanCurrent = function (nums) {
|
||||
// Step 1: Begin by initializing a [Frequency Map]()
|
||||
const freq = {};
|
||||
for (let n of nums) freq[n] = (freq[n] || 0) + 1;
|
||||
|
||||
// Step 2: Sort the numbers by ascending order
|
||||
const sorted = Object.keys(freq).sort((a, b) => a - b);
|
||||
|
||||
// Step 3: Init a count of numbers smaller than the active number
|
||||
let count = 0;
|
||||
|
||||
// Step 4: Init a map to track number of values smaller for each number
|
||||
const smaller = {};
|
||||
|
||||
// Step 5: Iterate over the sorted list
|
||||
for (let num of sorted) {
|
||||
// Set count for active number
|
||||
smaller[num] = count;
|
||||
|
||||
// Update the count by frequency
|
||||
count += freq[num];
|
||||
}
|
||||
|
||||
// Step 6: Use original list and find number of smaller values than it
|
||||
return nums.map((n) => smaller[n]);
|
||||
};
|
||||
```
|
||||
@@ -1,57 +0,0 @@
|
||||
---
|
||||
title: '1413. Minimum Value to Get Positive Step by Step Sum'
|
||||
description: Given an array of integers nums, you start with an initial positive value startValue
|
||||
sidebar:
|
||||
label: 'Minimum Value to Get Positive Step by Step Sum'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Array</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [-3,2,-3,4,2]`
|
||||
- Output: `5`
|
||||
- Explanation: If you choose `startValue = 4`, in the third iteration your step by step sum is less than `1`.
|
||||
|
||||
```
|
||||
step by step sum
|
||||
startValue = 4 | startValue = 5 | nums
|
||||
(4 -3 ) = 1 | (5 -3 ) = 2 | -3
|
||||
(1 +2 ) = 3 | (2 +2 ) = 4 | 2
|
||||
(3 -3 ) = 0 | (4 -3 ) = 1 | -3
|
||||
(0 +4 ) = 4 | (1 +4 ) = 5 | 4
|
||||
(4 +2 ) = 6 | (5 +2 ) = 7 | 2
|
||||
```
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [1,2]`
|
||||
- Output: `1`
|
||||
- Explanation: Minimum start value should be positive.
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [1,-2,-3]`
|
||||
- Output: `5`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 100`
|
||||
- `-100 <= nums[i] <= 100`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @return {number}
|
||||
*/
|
||||
var minStartValue = function(nums) {
|
||||
let prefix = [nums[0]];
|
||||
// Make prefix sum start at 1 after initializing seed value
|
||||
for (let i = 1; i < nums.length; i++){
|
||||
prefix.push(prefix[i - 1] + nums[i]);
|
||||
}
|
||||
|
||||
let min = Math.min(...prefix);
|
||||
return Math.max(1, 1 - min);
|
||||
};
|
||||
```
|
||||
@@ -1,45 +0,0 @@
|
||||
---
|
||||
title: '1426. Counting Elements'
|
||||
description: Given an integer array arr, count how many elements x there are, such that x + 1 is also in arr. If there are duplicates in arr, count them separately
|
||||
sidebar:
|
||||
label: 'Counting Elements'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Array</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `arr = [1,2,3]`
|
||||
- Output: `2`
|
||||
- Explanation: `1` and `2` are counted cause `2` and `3` are in `arr`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `arr = [1,1,3,3,5,5,7,7]`
|
||||
- Output: `0`
|
||||
- Explanation: No numbers are counted, cause there is no `2`, `4`, `6`, or `8` in `arr`.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= arr.length <= 1000`
|
||||
- `0 <= arr[i] <= 1000`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} arr
|
||||
* @return {number}
|
||||
*/
|
||||
var countElements = function(arr) {
|
||||
let arrSet = new Set(arr);
|
||||
let count = 0;
|
||||
|
||||
for (let n of arr) {
|
||||
let sum = n + 1;
|
||||
if (arrSet.has(sum)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
```
|
||||
@@ -1,44 +0,0 @@
|
||||
---
|
||||
title: '1480. Running Sum of 1d Array'
|
||||
description: Given an array nums. We define a running sum of an array as runningSum[i] = sum(nums[0]…nums[i])
|
||||
sidebar:
|
||||
label: 'Running Sum of 1d Array'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Array</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,2,3,4]`
|
||||
- Output: `[1,3,6,10]`
|
||||
- Explanation: Running sum is obtained as follows: `[1, 1+2, 1+2+3, 1+2+3+4]`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [1,1,1,1,1]`
|
||||
- Output: `[1,2,3,4,5]`
|
||||
- Explanation: Running sum is obtained as follows: `[1, 1+1, 1+1+1, 1+1+1+1, 1+1+1+1+1]`.
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [3,1,2,10,1]`
|
||||
- Output: `[3,4,6,16,17]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 1000`
|
||||
- `-10^6 <= nums[i] <= 10^6`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @return {number[]}
|
||||
*/
|
||||
var runningSum = function(nums) {
|
||||
let prefix = [nums[0]];
|
||||
for (let i = 1; i < nums.length; i++){
|
||||
prefix.push(prefix[i - 1] + nums[i]);
|
||||
}
|
||||
return prefix;
|
||||
};
|
||||
```
|
||||
@@ -1,78 +0,0 @@
|
||||
---
|
||||
title: '15. 3Sum'
|
||||
description: Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0
|
||||
sidebar:
|
||||
label: '3Sum'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Two Pointers</Badge>
|
||||
|
||||
::::warning
|
||||
Notice that the solution set must not contain duplicate triplets.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [-1,0,1,2,-1,-4]`
|
||||
- Output: `[[-1,-1,2],[-1,0,1]]`
|
||||
- Explanation: `nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0`. `nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0`. `nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0`. The distinct triplets are `[-1,0,1]` and `[-1,-1,2]`. Notice that the order of the output and the order of the triplets does not matter.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [0,1,1]`
|
||||
- Output: `[]`
|
||||
- Explanation: The only possible triplet does not sum up to `0`.
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [0,0,0]`
|
||||
- Output: `[[0,0,0]]`
|
||||
- Explanation: The only possible triplet sums up to `0`.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `3 <= nums.length <= 3000`
|
||||
- `-10^5 <= nums[i] <= 10^5`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def threeSum(self, nums: list[int]) -> list[list[int]]:
|
||||
nums.sort()
|
||||
result = []
|
||||
n = len(nums)
|
||||
|
||||
for i in range(n):
|
||||
# skip all zero
|
||||
if i > 0 and nums[i] == nums[i - 1]:
|
||||
continue
|
||||
|
||||
# two pointers
|
||||
left = i + 1
|
||||
right = n - 1
|
||||
target = -nums[i]
|
||||
|
||||
while left < right:
|
||||
current = nums[left] + nums[right]
|
||||
|
||||
if current == target:
|
||||
result.append([nums[i], nums[left], nums[right]])
|
||||
|
||||
# skip duplicates
|
||||
while left < right and nums[left] == nums[left + 1]:
|
||||
left += 1
|
||||
while left < right and nums[right] == nums[right - 1]:
|
||||
right -= 1
|
||||
|
||||
# shift pointers
|
||||
left += 1
|
||||
right -= 1
|
||||
|
||||
# since sorted, if current < target, then move left
|
||||
elif current < target:
|
||||
left += 1
|
||||
# since sorted, if current > target, then move right
|
||||
else:
|
||||
right -= 1
|
||||
|
||||
return result
|
||||
```
|
||||
@@ -1,42 +0,0 @@
|
||||
---
|
||||
title: '1636. Sort Array by Increasing Frequency'
|
||||
description: Given an array of integers nums, sort the array in increasing order based on the frequency of the values. If multiple values have the same frequency, sort them in decreasing order
|
||||
sidebar:
|
||||
label: 'Sort Array by Increasing Frequency'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Array</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,1,2,2,2,3]`
|
||||
- Output: `[3,1,1,2,2,2]`
|
||||
- Explanation: `'3'` has a frequency of `1`, `'1'` has a frequency of `2`, and `'2'` has a frequency of `3`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [2,3,1,3,2]`
|
||||
- Output: `[1,3,3,2,2]`
|
||||
- Explanation: `'2'` and `'3'` both have a frequency of `2`, so they are sorted in decreasing order.
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [-1,1,-6,4,5,-6,1,4,1]`
|
||||
- Output: `[5,-1,4,4,-6,-6,1,1,1]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 100`
|
||||
- `-100 <= nums[i] <= 100`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @return {number[]}
|
||||
*/
|
||||
var frequencySort = function (nums) {
|
||||
const freq = {};
|
||||
for (let n of nums) freq[n] = (freq[n] || 0) + 1;
|
||||
return nums.sort((a, b) => freq[a] - freq[b] || b - a);
|
||||
};
|
||||
```
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
title: '167. Two Sum II - Input Array Is Sorted'
|
||||
description: Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Let these two numbers be numbers[index1] and numbers[index2] where 1 <= index1 < index2 <= numbers.length
|
||||
sidebar:
|
||||
label: 'Two Sum II - Input Array Is Sorted'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Two Pointers</Badge>
|
||||
|
||||
::::warning
|
||||
Your solution must use only constant extra space.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `numbers = [2,7,11,15], target = 9`
|
||||
- Output: `[1,2]`
|
||||
- Explanation: The sum of `2` and `7` is `9`. Therefore, `index1 = 1`, `index2 = 2`. We return `[1, 2]`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `numbers = [2,3,4], target = 6`
|
||||
- Output: `[1,3]`
|
||||
- Explanation: The sum of `2` and `4` is `6`. Therefore `index1 = 1`, `index2 = 3`. We return `[1, 3]`.
|
||||
|
||||
### Example 3:
|
||||
- Input: `numbers = [-1,0], target = -1`
|
||||
- Output: `[1,2]`
|
||||
- Explanation: The sum of `-1` and `0` is `-1`. Therefore `index1 = 1`, `index2 = 2`. We return `[1, 2]`.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `2 <= numbers.length <= 3 * 10^4`
|
||||
- `-1000 <= numbers[i] <= 1000`
|
||||
- `numbers` is sorted in non-decreasing order.
|
||||
- `-1000 <= target <= 1000`
|
||||
- The tests are generated such that there is exactly one solution.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def twoSum(self, numbers: List[int], target: int) -> List[int]:
|
||||
i = 0
|
||||
j = len(numbers) - 1
|
||||
|
||||
while i < j:
|
||||
c = numbers[i] + numbers[j]
|
||||
if c == target:
|
||||
return [i + 1, j + 1]
|
||||
elif c < target:
|
||||
i+=1
|
||||
else:
|
||||
j-=1
|
||||
return []
|
||||
```
|
||||
@@ -1,42 +0,0 @@
|
||||
---
|
||||
title: '189. Rotate Array'
|
||||
description: Given an integer array nums, rotate the array to the right by k steps, where k is non-negative
|
||||
sidebar:
|
||||
label: 'Rotate Array'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Two Pointers</Badge>
|
||||
|
||||
::::warning
|
||||
Try to come up with as many solutions as you can. There are at least three different ways to solve this problem. Could you do it in-place with `O(1)` extra space?
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,2,3,4,5,6,7], k = 3`
|
||||
- Output: `[5,6,7,1,2,3,4]`
|
||||
- Explanation: rotate 1 steps to the right: `[7,1,2,3,4,5,6]` rotate 2 steps to the right: `[6,7,1,2,3,4,5]` rotate 3 steps to the right: `[5,6,7,1,2,3,4]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [-1,-100,3,99], k = 2`
|
||||
- Output: `[3,99,-1,-100]`
|
||||
- Explanation: rotate 1 steps to the right: `[99,-1,-100,3]` rotate 2 steps to the right: `[3,99,-1,-100]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^5`
|
||||
- `-2^31 <= nums[i] <= 2^31 - 1`
|
||||
- `0 <= k <= 10^5`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} k
|
||||
* @return {void} Do not return anything, modify nums in-place instead.
|
||||
*/
|
||||
var rotate = function(nums, k) {
|
||||
|
||||
};
|
||||
```
|
||||
@@ -1,50 +0,0 @@
|
||||
---
|
||||
title: '2090. K Radius Subarray Averages'
|
||||
description: You are given a 0-indexed array nums of n integers, and an integer k
|
||||
sidebar:
|
||||
label: 'K Radius Subarray Averages'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Array</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [7,4,3,9,1,8,5,2,6], k = 3`
|
||||
- Output: `[-1,-1,-1,5,4,4,-1,-1,-1]`
|
||||
- Explanation:
|
||||
- `avg[0]`, `avg[1]`, and `avg[2]` are `-1` because there are less than `k` elements before each index.
|
||||
- The sum of the subarray centered at index `3` with radius `3` is: `7 + 4 + 3 + 9 + 1 + 8 + 5 = 37`. Using integer division, `avg[3] = 37 / 7 = 5`.
|
||||
- For the subarray centered at index `4`, `avg[4] = (4 + 3 + 9 + 1 + 8 + 5 + 2) / 7 = 4`.
|
||||
- For the subarray centered at index `5`, `avg[5] = (3 + 9 + 1 + 8 + 5 + 2 + 6) / 7 = 4`.
|
||||
- `avg[6]`, `avg[7]`, and `avg[8]` are `-1` because there are less than `k` elements after each index.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [100000], k = 0`
|
||||
- Output: `[100000]`
|
||||
- Explanation:
|
||||
- The sum of the subarray centered at index `0` with radius `0` is: `100000`. `avg[0] = 100000 / 1 = 100000`.
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [8], k = 100000`
|
||||
- Output: `[-1]`
|
||||
- Explanation:
|
||||
- `avg[0]` is `-1` because there are less than `k` elements before and after index `0`.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `n == nums.length`
|
||||
- `1 <= n <= 10^5`
|
||||
- `0 <= nums[i], k <= 10^5`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} k
|
||||
* @return {number[]}
|
||||
*/
|
||||
var getAverages = function(nums, k) {
|
||||
|
||||
};
|
||||
```
|
||||
@@ -1,47 +0,0 @@
|
||||
---
|
||||
title: '217. Contains Duplicate'
|
||||
description: Given an integer array nums, return true if any value appears at least twice in the array, and return false if every element is distinct
|
||||
sidebar:
|
||||
label: 'Contains Duplicate'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Hash Table</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,2,3,1]`
|
||||
- Output: `true`
|
||||
- Explanation: The element `1` occurs at the indices `0` and `3`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [1,2,3,4]`
|
||||
- Output: `false`
|
||||
- Explanation: All elements are distinct.
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [1,1,1,3,3,4,3,2,4,2]`
|
||||
- Output: `true`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^5`
|
||||
- `-10^9 <= nums[i] <= 10^9`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @return {boolean}
|
||||
*/
|
||||
var containsDuplicate = function(nums) {
|
||||
const freq = {};
|
||||
for (let n of nums) {
|
||||
freq[n] = (freq[n] || 0) + 1;
|
||||
if (freq[n] >= 2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
```
|
||||
@@ -1,53 +0,0 @@
|
||||
---
|
||||
title: '238. Product of Array Except Self'
|
||||
description: Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i]
|
||||
sidebar:
|
||||
label: 'Product of Array Except Self'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Prefix Sum</Badge>
|
||||
|
||||
::::warning
|
||||
You must write an algorithm that runs in O(n) time and without using the division operation.
|
||||
Can you solve the problem in O(1) extra space complexity? (The output array does not count as extra space for space complexity analysis.)
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,2,3,4]`
|
||||
- Output: `[24,12,8,6]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [-1,1,0,-3,3]`
|
||||
- Output: `[0,0,9,0,0]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `2 <= nums.length <= 10^5`
|
||||
- `-30 <= nums[i] <= 30`
|
||||
- The input is generated such that `answer[i]` is guaranteed to fit in a 32-bit integer.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @return {number[]}
|
||||
*/
|
||||
var productExceptSelf = function(nums) {
|
||||
const n = nums.length;
|
||||
const answer = new Array(n).fill(1);
|
||||
const rightArr = new Array(n).fill(1);
|
||||
|
||||
for (let i = 1; i < n; i++) {
|
||||
answer[i] = nums[i - 1] * answer[i - 1];
|
||||
}
|
||||
for (let i = n - 2; i >= 0; i--) {
|
||||
rightArr[i] = nums[i + 1] * rightArr[i + 1];
|
||||
}
|
||||
for (let i = 0; i < n; i++) {
|
||||
answer[i] *= rightArr[i];
|
||||
}
|
||||
return answer;
|
||||
};
|
||||
```
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
title: '268. Missing Number'
|
||||
description: Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array
|
||||
sidebar:
|
||||
label: 'Missing Number'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Array</Badge>
|
||||
|
||||
::::warning
|
||||
Could you implement a solution using only O(1) extra space complexity and O(n) runtime complexity?
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [3,0,1]`
|
||||
- Output: `2`
|
||||
- Explanation: `n = 3` since there are `3` numbers, so all numbers are in the range `[0,3]`. `2` is the missing number in the range since it does not appear in `nums`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [0,1]`
|
||||
- Output: `2`
|
||||
- Explanation: `n = 2` since there are `2` numbers, so all numbers are in the range `[0,2]`. `2` is the missing number in the range since it does not appear in `nums`.
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [9,6,4,2,3,5,7,0,1]`
|
||||
- Output: `8`
|
||||
- Explanation: `n = 9` since there are `9` numbers, so all numbers are in the range `[0,9]`. `8` is the missing number in the range since it does not appear in `nums`.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `n == nums.length`
|
||||
- `1 <= n <= 10^4`
|
||||
- `0 <= nums[i] <= n`
|
||||
- All the numbers of `nums` are unique.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @return {number}
|
||||
*/
|
||||
var missingNumber = function(nums) {
|
||||
const numSet = new Set(nums);
|
||||
const expectedCount = nums.length + 1;
|
||||
|
||||
for (let i = 0; i < expectedCount; i++){
|
||||
if(!numSet.has(i)){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
```
|
||||
@@ -1,52 +0,0 @@
|
||||
---
|
||||
title: '303. Range Sum Query - Immutable'
|
||||
description: Given an integer array nums, handle multiple queries of the following type
|
||||
sidebar:
|
||||
label: 'Range Sum Query - Immutable'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Prefix Sum</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `["NumArray", "sumRange", "sumRange", "sumRange"]` `[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]`
|
||||
- Output: `[null, 1, -1, -3]`
|
||||
- Explanation: `NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);` `numArray.sumRange(0, 2); // return (-2) + 0 + 3 = 1` `numArray.sumRange(2, 5); // return 3 + (-5) + 2 + (-1) = -1` `numArray.sumRange(0, 5); // return (-2) + 0 + 3 + (-5) + 2 + (-1) = -3`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^4`
|
||||
- `-10^5 <= nums[i] <= 10^5`
|
||||
- `0 <= left <= right < nums.length`
|
||||
- At most `10^4` calls will be made to `sumRange`.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
*/
|
||||
class NumArray {
|
||||
constructor(nums) {
|
||||
this.prefix = [0];
|
||||
for (let n of nums){
|
||||
this.prefix.push(this.prefix[this.prefix.length - 1] + n);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {number} left
|
||||
* @param {number} right
|
||||
* @return {number}
|
||||
*/
|
||||
sumRange(left, right) {
|
||||
return this.prefix[right + 1] - this.prefix[left];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Your NumArray object will be instantiated and called as such:
|
||||
* var obj = new NumArray(nums)
|
||||
* var param_1 = obj.sumRange(left,right)
|
||||
*/
|
||||
```
|
||||
@@ -1,71 +0,0 @@
|
||||
---
|
||||
title: '33. Search in Rotated Sorted Array'
|
||||
description: There is an integer array nums sorted in ascending order (with distinct values)
|
||||
sidebar:
|
||||
label: 'Search in Rotated Sorted Array'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Binary Search</Badge>
|
||||
|
||||
::::warning
|
||||
You must write an algorithm with O(log n) runtime complexity.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [4,5,6,7,0,1,2], target = 0`
|
||||
- Output: `4`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [4,5,6,7,0,1,2], target = 3`
|
||||
- Output: `-1`
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [1], target = 0`
|
||||
- Output: `-1`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 5000`
|
||||
- `-10^4 <= nums[i] <= 10^4`
|
||||
- All values of `nums` are unique.
|
||||
- `nums` is an ascending array that is possibly rotated.
|
||||
- `-10^4 <= target <= 10^4`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} target
|
||||
* @return {number}
|
||||
*/
|
||||
var search = function(nums, target) {
|
||||
let l = 0, r = nums.length - 1;
|
||||
|
||||
while (l <= r){
|
||||
let mid = Math.floor((l + r)/2);
|
||||
if (target === nums[mid]) {
|
||||
return mid
|
||||
}
|
||||
|
||||
// Left sorted portion
|
||||
if (nums[l] <= nums[mid]){
|
||||
if (target > nums[mid] || target < nums[l]){
|
||||
l = mid + 1;
|
||||
}else{
|
||||
r = mid - 1;
|
||||
}
|
||||
}
|
||||
// Right sorted portion
|
||||
else{
|
||||
if(target < nums[mid] || target > nums[r]){
|
||||
r = mid - 1;
|
||||
}else{
|
||||
l = mid + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
```
|
||||
@@ -1,51 +0,0 @@
|
||||
---
|
||||
title: '347. Top K Frequent Elements'
|
||||
description: Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order
|
||||
sidebar:
|
||||
label: 'Top K Frequent Elements'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Hash Table</Badge>
|
||||
|
||||
::::warning
|
||||
Your algorithm's time complexity must be better than O(n log n), where n is the array's size.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,1,1,2,2,3], k = 2`
|
||||
- Output: `[1,2]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [1], k = 1`
|
||||
- Output: `[1]`
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [1,2,1,2,1,2,3,1,3,2], k = 2`
|
||||
- Output: `[1,2]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^5`
|
||||
- `-10^4 <= nums[i] <= 10^4`
|
||||
- `k` is in the range `[1, the number of unique elements in the array]`.
|
||||
- It is guaranteed that the answer is unique.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} k
|
||||
* @return {number[]}
|
||||
*/
|
||||
var topKFrequent = function (nums, k) {
|
||||
const freq = {};
|
||||
for (let n of nums) freq[n] = (freq[n] || 0) + 1;
|
||||
|
||||
return Object.keys(freq)
|
||||
.map(Number)
|
||||
.sort((a, b) => freq[b] - freq[a])
|
||||
.slice(0, k);
|
||||
};
|
||||
```
|
||||
@@ -1,36 +0,0 @@
|
||||
---
|
||||
title: '42. Trapping Rain Water'
|
||||
description: Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining
|
||||
sidebar:
|
||||
label: 'Trapping Rain Water'
|
||||
badge: 'Hard'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Two Pointers</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `height = [0,1,0,2,1,0,1,3,2,1,2,1]`
|
||||
- Output: `6`
|
||||
- Explanation: The above elevation map (black section) is represented by array `[0,1,0,2,1,0,1,3,2,1,2,1]`. In this case, `6` units of rain water (blue section) are being trapped.
|
||||
|
||||
### Example 2:
|
||||
- Input: `height = [4,2,0,3,2,5]`
|
||||
- Output: `9`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `n == height.length`
|
||||
- `1 <= n <= 2 * 10^4`
|
||||
- `0 <= height[i] <= 10^5`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} height
|
||||
* @return {number}
|
||||
*/
|
||||
var trap = function(height) {
|
||||
|
||||
};
|
||||
```
|
||||
@@ -1,51 +0,0 @@
|
||||
---
|
||||
title: '49. Group Anagrams'
|
||||
description: Given an array of strings strs, group the anagrams together. You can return the answer in any order
|
||||
sidebar:
|
||||
label: 'Group Anagrams'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Hash Table</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `strs = ["eat","tea","tan","ate","nat","bat"]`
|
||||
- Output: `[["bat"],["nat","tan"],["ate","eat","tea"]]`
|
||||
- Explanation: There is no string in `strs` that can be rearranged to form `"bat"`. The strings `"nat"` and `"tan"` are anagrams as they can be rearranged to form each other. The strings `"ate"`, `"eat"`, and `"tea"` are anagrams as they can be rearranged to form each other.
|
||||
|
||||
### Example 2:
|
||||
- Input: `strs = [""]`
|
||||
- Output: `[[""]]`
|
||||
|
||||
### Example 3:
|
||||
- Input: `strs = ["a"]`
|
||||
- Output: `[["a"]]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= strs.length <= 10^4`
|
||||
- `0 <= strs[i].length <= 100`
|
||||
- `strs[i]` consists of lowercase English letters.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {string[]} strs
|
||||
* @return {string[][]}
|
||||
*/
|
||||
var groupAnagrams = function(strs) {
|
||||
let sorted = strs.map(str => str.split("").sort().join(""));
|
||||
let anagrams = {};
|
||||
|
||||
for (let i = 0; i < strs.length; i++){
|
||||
if(!anagrams[sorted[i]]){
|
||||
anagrams[sorted[i]] = [strs[i]]
|
||||
}else{
|
||||
anagrams[sorted[i]].push(strs[i])
|
||||
}
|
||||
}
|
||||
|
||||
return Object.values(anagrams);
|
||||
};
|
||||
```
|
||||
@@ -1,51 +0,0 @@
|
||||
---
|
||||
title: '560. Subarray Sum Equals K'
|
||||
description: Given an array of integers nums and an integer k, return the total number of subarrays whose sum equals to k
|
||||
sidebar:
|
||||
label: 'Subarray Sum Equals K'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Prefix Sum</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,1,1], k = 2`
|
||||
- Output: `2`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [1,2,3], k = 3`
|
||||
- Output: `2`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 2 * 10^4`
|
||||
- `-1000 <= nums[i] <= 1000`
|
||||
- `-10^7 <= k <= 10^7`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} k
|
||||
* @return {number}
|
||||
*/
|
||||
var subarraySum = function(nums, k) {
|
||||
const map = new Map();
|
||||
map.set(0, 1);
|
||||
|
||||
let sum = 0;
|
||||
let count = 0;
|
||||
|
||||
for (let n of nums){
|
||||
sum += n;
|
||||
|
||||
if(map.has(sum - k)){
|
||||
count += map.get(sum - k);
|
||||
}
|
||||
|
||||
map.set(sum, (map.get(sum) || 0) + 1);
|
||||
}
|
||||
return count
|
||||
};
|
||||
```
|
||||
@@ -1,56 +0,0 @@
|
||||
---
|
||||
title: '704. Binary Search'
|
||||
description: Given an array of integers nums which is sorted in ascending order, and an integer target, write a function to search target in nums. If target exists, then return its index. Otherwise, return -1
|
||||
sidebar:
|
||||
label: 'Binary Search'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Binary Search</Badge>
|
||||
|
||||
::::warning
|
||||
You must write an algorithm with O(log n) runtime complexity.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [-1,0,3,5,9,12], target = 9`
|
||||
- Output: `4`
|
||||
- Explanation: `9` exists in `nums` and its index is `4`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [-1,0,3,5,9,12], target = 2`
|
||||
- Output: `-1`
|
||||
- Explanation: `2` does not exist in `nums` so return `-1`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^4`
|
||||
- `-10^4 < nums[i], target < 10^4`
|
||||
- All the integers in `nums` are unique.
|
||||
- `nums` is sorted in ascending order.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} target
|
||||
* @return {number}
|
||||
*/
|
||||
var search = function(nums, target) {
|
||||
let left = 0;
|
||||
let right = nums.length - 1;
|
||||
|
||||
while(left <= right) {
|
||||
const mid = left + Math.floor((right - left) / 2);
|
||||
if (nums[mid] === target) {
|
||||
return mid;
|
||||
} else if(nums[mid] < target){
|
||||
left = mid + 1;
|
||||
} else if (nums[mid] > target) {
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
```
|
||||
@@ -1,62 +0,0 @@
|
||||
---
|
||||
title: '875. Koko Eating Bananas'
|
||||
description: Koko loves to eat bananas. There are n piles of bananas, the i^th pile has piles[i] bananas. The guards have gone and will come back in h hours
|
||||
sidebar:
|
||||
label: 'Koko Eating Bananas'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Binary Search</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `piles = [3,6,7,11], h = 8`
|
||||
- Output: `4`
|
||||
|
||||
### Example 2:
|
||||
- Input: `piles = [30,11,23,4,20], h = 5`
|
||||
- Output: `30`
|
||||
|
||||
### Example 3:
|
||||
- Input: `piles = [30,11,23,4,20], h = 6`
|
||||
- Output: `23`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= piles.length <= 10^4`
|
||||
- `piles.length <= h <= 10^9`
|
||||
- `1 <= piles[i] <= 10^9`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} piles
|
||||
* @param {number} h
|
||||
* @return {number}
|
||||
*/
|
||||
var minEatingSpeed = function(piles, h) {
|
||||
// Function to determine if K works for the H
|
||||
function kWorks(k){
|
||||
let hours = 0;
|
||||
for (let p of piles){
|
||||
hours += Math.ceil(p/k)
|
||||
}
|
||||
return hours <= h;
|
||||
}
|
||||
|
||||
// Setup Binary Search
|
||||
let l = 1;
|
||||
let r = Math.max(...piles);
|
||||
|
||||
// Find the K value which works for H and consumes all bananas
|
||||
while (l < r){
|
||||
const mid = Math.floor((l + r) / 2);
|
||||
if (kWorks(mid)){
|
||||
r = mid;
|
||||
}else{
|
||||
l = mid + 1;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
};
|
||||
```
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
title: '977. Squares of a Sorted Array'
|
||||
description: Given an integer array nums sorted in non-decreasing order, return an array of the squares of each number sorted in non-decreasing order
|
||||
sidebar:
|
||||
label: 'Squares of a Sorted Array'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Two Pointers</Badge>
|
||||
|
||||
::::warning
|
||||
Squaring each element and sorting the new array is very trivial, could you find an O(n) solution using a different approach?
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [-4,-1,0,3,10]`
|
||||
- Output: `[0,1,9,16,100]`
|
||||
- Explanation: After squaring, the array becomes `[16,1,0,9,100]`. After sorting, it becomes `[0,1,9,16,100]`.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [-7,-3,2,3,11]`
|
||||
- Output: `[4,9,9,49,121]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^4`
|
||||
- `-10^4 <= nums[i] <= 10^4`
|
||||
- `nums` is sorted in non-decreasing order.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @return {number[]}
|
||||
*/
|
||||
var sortedSquares = function(nums) {
|
||||
let n = nums.length;
|
||||
let ans = new Array(nums.length);
|
||||
let left = 0, right = nums.length - 1;
|
||||
|
||||
for (let i = n -1; i >= 0; i--){
|
||||
let square;
|
||||
if(Math.abs(nums[left]) < Math.abs(nums[right])){
|
||||
square = nums[right];
|
||||
right--;
|
||||
}else{
|
||||
square = nums[left];
|
||||
left++;
|
||||
}
|
||||
ans[i] = square*square;
|
||||
}
|
||||
return ans;
|
||||
};
|
||||
```
|
||||
@@ -1,41 +0,0 @@
|
||||
---
|
||||
title: '1832. Check if the Sentence Is Pangram'
|
||||
description: A pangram is a sentence where every letter of the English alphabet appears at least once
|
||||
sidebar:
|
||||
label: 'Check if the Sentence Is Pangram'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Hash Table</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `sentence = "thequickbrownfoxjumpsoverthelazydog"`
|
||||
- Output: `true`
|
||||
- Explanation: `sentence` contains at least one of every letter of the English alphabet.
|
||||
|
||||
### Example 2:
|
||||
- Input: `sentence = "leetcode"`
|
||||
- Output: `false`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= sentence.length <= 1000`
|
||||
- `sentence` consists of lowercase English letters.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {string} sentence
|
||||
* @return {boolean}
|
||||
*/
|
||||
var checkIfPangram = function(sentence) {
|
||||
const freq = {};
|
||||
for (let c of sentence) freq[c] = (freq[c] || 0) + 1;
|
||||
|
||||
if (Object.keys(freq).length === 26){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
```
|
||||
@@ -1,48 +0,0 @@
|
||||
---
|
||||
title: '242. Valid Anagram'
|
||||
description: Given two strings s and t, return true if t is an anagram of s, and false otherwise
|
||||
sidebar:
|
||||
label: 'Valid Anagram'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Hash Table</Badge>
|
||||
|
||||
::::warning
|
||||
What if the inputs contain Unicode characters? How would you adapt your solution to such a case?
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "anagram", t = "nagaram"`
|
||||
- Output: `true`
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "rat", t = "car"`
|
||||
- Output: `false`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length, t.length <= 5 * 10^4`
|
||||
- `s` and `t` consist of lowercase English letters.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {string} s
|
||||
* @param {string} t
|
||||
* @return {boolean}
|
||||
*/
|
||||
var isAnagram = function(s, t) {
|
||||
let freq = {};
|
||||
for (let c of s) freq[c] = (freq[c] || 0) + 1;
|
||||
|
||||
for (let c of t) {
|
||||
if(!freq[c] || freq[c] === 0){
|
||||
return false;
|
||||
}
|
||||
freq[c] = freq[c] - 1;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
```
|
||||
@@ -1,47 +0,0 @@
|
||||
---
|
||||
title: '387. First Unique Character in a String'
|
||||
description: Given a string s, find the first non-repeating character in it and return its index. If it does not exist, return -1
|
||||
sidebar:
|
||||
label: 'First Unique Character in a String'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Hash Table</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "leetcode"`
|
||||
- Output: `0`
|
||||
- Explanation: The character `'l'` at index `0` is the first character that does not occur at any other index.
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "loveleetcode"`
|
||||
- Output: `2`
|
||||
|
||||
### Example 3:
|
||||
- Input: `s = "aabb"`
|
||||
- Output: `-1`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length <= 10^5`
|
||||
- `s` consists of only lowercase English letters.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {string} s
|
||||
* @return {number}
|
||||
*/
|
||||
var firstUniqChar = function (s) {
|
||||
const freq = {};
|
||||
for (let c of s) freq[c] = (freq[c] || 0) + 1;
|
||||
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
if (freq[s[i]] === 1) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
```
|
||||
@@ -1,49 +0,0 @@
|
||||
---
|
||||
title: '451. Sort Characters By Frequency'
|
||||
description: Given a string s, sort it in decreasing order based on the frequency of the characters. The frequency of a character is the number of times it appears in the string
|
||||
sidebar:
|
||||
label: 'Sort Characters By Frequency'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Hash Table</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "tree"`
|
||||
- Output: `"eert"`
|
||||
- Explanation: `'e'` appears twice while `'r'` and `'t'` both appear once. So `'e'` must appear before both `'r'` and `'t'`. Therefore `"eetr"` is also a valid answer.
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "cccaaa"`
|
||||
- Output: `"aaaccc"`
|
||||
- Explanation: Both `'c'` and `'a'` appear three times, so both `"cccaaa"` and `"aaaccc"` are valid answers. Note that `"cacaca"` is incorrect, as the same characters must be together.
|
||||
|
||||
### Example 3:
|
||||
- Input: `s = "Aabb"`
|
||||
- Output: `"bbAa"`
|
||||
- Explanation: `"bbaA"` is also a valid answer, but `"Aabb"` is incorrect. Note that `'A'` and `'a'` are treated as two different characters.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length <= 5 * 10^5`
|
||||
- `s` consists of uppercase and lowercase English letters and digits.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {string} s
|
||||
* @return {string}
|
||||
*/
|
||||
var frequencySort = function (s) {
|
||||
// count the frequency of each character
|
||||
const freq = {};
|
||||
for (let c of s) freq[c] = (freq[c] || 0) + 1;
|
||||
|
||||
// sort the characters by frequency
|
||||
return s
|
||||
.split("")
|
||||
.sort((a, b) => freq[b] - freq[a] || a.localeCompare(b))
|
||||
.join("");
|
||||
};
|
||||
```
|
||||
@@ -1,51 +0,0 @@
|
||||
---
|
||||
title: '125. Valid Palindrome'
|
||||
description: A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters include letters and numbers
|
||||
sidebar:
|
||||
label: 'Valid Palindrome'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Two Pointers</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "A man, a plan, a canal: Panama"`
|
||||
- Output: `true`
|
||||
- Explanation: `"amanaplanacanalpanama"` is a palindrome.
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "race a car"`
|
||||
- Output: `false`
|
||||
- Explanation: `"raceacar"` is not a palindrome.
|
||||
|
||||
### Example 3:
|
||||
- Input: `s = " "`
|
||||
- Output: `true`
|
||||
- Explanation: `s` is an empty string `""` after removing non-alphanumeric characters. Since an empty string reads the same forward and backward, it is a palindrome.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length <= 2 * 10^5`
|
||||
- `s` consists only of printable ASCII characters.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {string} s
|
||||
* @return {boolean}
|
||||
*/
|
||||
var isPalindrome = function(s) {
|
||||
let normal = s.replace(/[^a-zA-Z0-9]/g, "").toLowerCase()
|
||||
let i = 0, j = normal.length - 1;
|
||||
|
||||
while (i < j) {
|
||||
if(normal[i] !== normal[j]) {
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
j--;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
```
|
||||
@@ -1,45 +0,0 @@
|
||||
---
|
||||
title: '344. Reverse String'
|
||||
description: Write a function that reverses a string. The input string is given as an array of characters s
|
||||
sidebar:
|
||||
label: 'Reverse String'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Two Pointers</Badge>
|
||||
|
||||
:::warning
|
||||
You must do this by modifying the input array in-place with O(1) extra memory.
|
||||
:::
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = ["h","e","l","l","o"]`
|
||||
- Output: `["o","l","l","e","h"]`
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = ["H","a","n","n","a","h"]`
|
||||
- Output: `["h","a","n","n","a","H"]`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length <= 10^5`
|
||||
- `s[i]` is a printable ascii character.
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {character[]} s
|
||||
* @return {void} Do not return anything, modify s in-place instead.
|
||||
*/
|
||||
var reverseString = function(s) {
|
||||
let i = 0;
|
||||
let j = s.length - 1;
|
||||
|
||||
while (i < j) {
|
||||
[s[i], s[j]] = [s[j], s[i]];
|
||||
j--;
|
||||
i++;
|
||||
}
|
||||
};
|
||||
```
|
||||
@@ -1,44 +0,0 @@
|
||||
---
|
||||
title: '392. Is Subsequence'
|
||||
description: Given two strings s and t, return true if s is a subsequence of t, or false otherwise
|
||||
sidebar:
|
||||
label: 'Is Subsequence'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Two Pointers</Badge>
|
||||
|
||||
::::warning
|
||||
Suppose there are lots of incoming s, say s1, s2, ..., sk where k >= 10^9, and you want to check one by one to see if t has its subsequence. In this scenario, how would you change your code?
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "abc", t = "ahbgdc"`
|
||||
- Output: `true`
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "axc", t = "ahbgdc"`
|
||||
- Output: `false`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `0 <= s.length <= 100`
|
||||
- `0 <= t.length <= 10^4`
|
||||
- `s` and `t` consist only of lowercase English letters.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def isSubsequence(self, s: str, t: str) -> bool:
|
||||
if len(s) > len(t):
|
||||
return False
|
||||
|
||||
i, j = 0, 0
|
||||
while i < len(s) and j < len(t):
|
||||
if s[i] == t[j]:
|
||||
i += 1
|
||||
j += 1
|
||||
|
||||
return i == len(s)
|
||||
```
|
||||
Reference in new issue
Block a user