Compare commits
35 Commits
ab80017903
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| e10cc4257d | |||
| c67841fe07 | |||
| 14d05011d5 | |||
| 0aed1528e2 | |||
| 0f9312eaee | |||
| c9fe2fab76 | |||
| 03561f8d10 | |||
| fc6e664ff9 | |||
| 7659303fb0 | |||
| cf158eafdf | |||
| 1dec88aaf2 | |||
| e798e449bd | |||
| d674451070 | |||
| a50f4a121b | |||
| 1853f99367 | |||
| 702213e83e | |||
| dfadc1ca48 | |||
| 1d88296bf6 | |||
| 956c2b2c88 | |||
| eabb433ec6 | |||
| 7371b2617d | |||
| 142f2469ec | |||
| b4f25ab87b | |||
| f603236a48 | |||
| fa64e776ca | |||
| 127aad7003 | |||
| defa2145e8 | |||
| 978ab00faa | |||
| 3ab8ba001d | |||
| 69676a84be | |||
| 6b9a0d3161 | |||
| eaed0664f3 | |||
| ffdbb39158 | |||
| 09ce69a51a | |||
| dc6ab90c03 |
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"initialized": true,
|
||||||
|
"learning_mode": "balanced",
|
||||||
|
"macos_reminders_enabled": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# C++ Pointers and References - Mastery Checklist
|
||||||
|
|
||||||
|
## Core Concepts
|
||||||
|
|
||||||
|
Track your understanding of key concepts:
|
||||||
|
|
||||||
|
- [ ] Declaration syntax: & and * placement
|
||||||
|
- [ ] Pointers vs references: mental model
|
||||||
|
- [ ] Pointer arithmetic
|
||||||
|
- [ ] const correctness with pointers and references
|
||||||
|
- [ ] References as function parameters
|
||||||
|
- [ ] Pointer-to-pointer
|
||||||
|
- [ ] Null pointers and nullptr
|
||||||
|
- [ ] Dangling pointers and references
|
||||||
|
- [ ] Smart pointers (unique_ptr, shared_ptr, weak_ptr)
|
||||||
|
- [ ] Lvalue references vs rvalue references
|
||||||
|
- [ ] Move semantics
|
||||||
|
- [ ] Perfect forwarding
|
||||||
|
- [ ] Reference collapsing rules
|
||||||
|
- [ ] Common interview traps
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"topic": "C++ Pointers and References",
|
||||||
|
"created_at": "2026-05-20T12:00:00",
|
||||||
|
"status": "in_progress",
|
||||||
|
"syllabus_generated": true,
|
||||||
|
"total_sessions": 0,
|
||||||
|
"last_session": null,
|
||||||
|
"last_reviewed": null
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# C++ Pointers and References - Learning Progress
|
||||||
|
|
||||||
|
## Daily Logs
|
||||||
|
|
||||||
|
<!-- Daily learning entries will be added here -->
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"reviews": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
# C++ Pointers and References — Syllabus
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Master C++ indirection mechanisms from declaration syntax through move semantics. Emphasis on building correct mental models, real-world usage patterns, and surviving interview questions about pointers and references.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Basic C++ syntax (variables, functions, structs/classes)
|
||||||
|
- Understanding of stack vs heap (conceptual)
|
||||||
|
|
||||||
|
## Learning Objectives
|
||||||
|
|
||||||
|
By completion you will be able to:
|
||||||
|
- Read and write any pointer/reference declaration confidently
|
||||||
|
- Explain the difference between `&`/`*` in declarations vs expressions
|
||||||
|
- Use const-correctness with pointers and references correctly
|
||||||
|
- Understand ownership semantics and choose the right smart pointer
|
||||||
|
- Handle move semantics and forwarding references
|
||||||
|
- Answer common interview questions on pointers and references
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 1: Foundations — Declaration Syntax & Mental Models
|
||||||
|
|
||||||
|
- [ ] `&` and `*` in declarations vs expressions — the two contexts
|
||||||
|
- [ ] Does `*` / `&` bind to the type or the variable? (C++ parsing rules)
|
||||||
|
- [ ] Multiple declarations on one line: `int *a, b` — what is b?
|
||||||
|
- [ ] Pointers: what they are (address), what they hold, how to dereference
|
||||||
|
- [ ] References: what they are (alias), how they differ from pointers
|
||||||
|
- [ ] Pointer vs reference: when to use which (guidelines)
|
||||||
|
- [ ] Null pointers: NULL vs nullptr vs 0
|
||||||
|
|
||||||
|
**Teaching Milestone:** Explain the "declaration follows use" principle to a beginner.
|
||||||
|
|
||||||
|
## Phase 2: const Correctness & Function Signatures
|
||||||
|
|
||||||
|
- [ ] `const int*` vs `int* const` vs `const int* const`
|
||||||
|
- [ ] `const int&` — why it's the default parameter style
|
||||||
|
- [ ] Top-level const vs low-level const
|
||||||
|
- [ ] East const vs West const style
|
||||||
|
- [ ] Passing by value vs by reference vs by pointer — tradeoffs
|
||||||
|
- [ ] Return by reference: when safe, when dangerous
|
||||||
|
- [ ] Pointer arithmetic basics
|
||||||
|
|
||||||
|
**Teaching Milestone:** Read a complex function signature and explain what each parameter accepts and whether it can be modified.
|
||||||
|
|
||||||
|
## Phase 3: Ownership & Smart Pointers
|
||||||
|
|
||||||
|
- [ ] Raw pointer ownership problems (leaks, double free, dangling)
|
||||||
|
- [ ] RAII principle
|
||||||
|
- [ ] `std::unique_ptr` — exclusive ownership
|
||||||
|
- [ ] `std::shared_ptr` — shared ownership and reference counting
|
||||||
|
- [ ] `std::weak_ptr` — breaking cycles
|
||||||
|
- [ ] Choosing the right smart pointer (decision tree)
|
||||||
|
- [ ] `std::make_unique` / `std::make_shared` — why prefer them
|
||||||
|
|
||||||
|
**Teaching Milestone:** Refactor a raw-pointer design to use smart pointers and explain your choices.
|
||||||
|
|
||||||
|
## Phase 4: Move Semantics & Advanced References
|
||||||
|
|
||||||
|
- [ ] Lvalue vs rvalue — what are they really
|
||||||
|
- [ ] Lvalue references (`T&`) vs rvalue references (`T&&`)
|
||||||
|
- [ ] `std::move` — what it does and doesn't do
|
||||||
|
- [ ] Move constructors and move assignment
|
||||||
|
- [ ] Reference collapsing rules
|
||||||
|
- [ ] Forwarding references (`T&&` in templates)
|
||||||
|
- [ ] `std::forward` — perfect forwarding
|
||||||
|
- [ ] Common interview traps and trick questions
|
||||||
|
|
||||||
|
**Teaching Milestone:** Explain why `std::move` doesn't actually move anything.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- cppreference.com — authoritative reference
|
||||||
|
- "Effective Modern C++" by Scott Meyers — Items 1-6, 23-26
|
||||||
|
- Herb Sutter's GotW articles on const correctness
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
- Can read any declaration with `*`, `&`, `const` and explain it
|
||||||
|
- Can choose between pointer, reference, and smart pointer for any use case
|
||||||
|
- Can explain move semantics without hand-waving
|
||||||
|
- Can spot pointer/reference bugs in code review
|
||||||
@@ -31,3 +31,23 @@ code
|
|||||||
|
|
||||||
## Self-Improvement
|
## Self-Improvement
|
||||||
Periodically review this file and suggest improvements to the user if you notice gaps, inconsistencies, or missing conventions.
|
Periodically review this file and suggest improvements to the user if you notice gaps, inconsistencies, or missing conventions.
|
||||||
|
|
||||||
|
## Subdirectories
|
||||||
|
- `leetcode/` — NeetCode roadmap extractor (dependency graph + problem list). See `leetcode/AGENTS.md`.
|
||||||
|
- `org/study_deck_02/` — Anki study deck for NeetCode DSA problems. See `org/study_deck_02/AGENTS.md`.
|
||||||
|
- `org/cpp/` — C++ flashcard notes (non-DSA topics: containers, iterators, etc.)
|
||||||
|
|
||||||
|
## LeetCode Workflow
|
||||||
|
- `org/study_deck_02/roadmap.org` — tracker only (`**` headings, `g c c` to toggle DONE)
|
||||||
|
- `org/study_deck_02/dsa/<topic>/<problem>.org` — your notes, solutions, flashcards
|
||||||
|
- Each links to the other via org file links
|
||||||
|
- Problem tags (`:easy:`, `:medium:`, `:hard:`) enable filtering with `/ t`
|
||||||
|
|
||||||
|
## Active Context
|
||||||
|
<!-- AI assistant maintains this section. Keep under 20 lines. -->
|
||||||
|
<!-- Updated automatically by /self-improve. Remove stale entries. -->
|
||||||
|
- Branch: `master`, up to date with origin
|
||||||
|
- DSA notes moved from `org/cpp/dsa/` to `org/study_deck_02/dsa/`
|
||||||
|
- All files carry `#+ANKI_DECK: study_deck_02` for org-anki export
|
||||||
|
- Inbox items: binary search, `using` keyword — need cards created
|
||||||
|
- Possible cleanup: `org/study_deck_02/dsa/udfs.org` may be a stale draft of `org/cpp/ufds.org`
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Project Learnings
|
||||||
|
|
||||||
|
> Auto-maintained by the self-improve skill. Read at session start, updated at session end.
|
||||||
|
|
||||||
|
## Patterns That Work
|
||||||
|
<!-- Approaches that produced good results -->
|
||||||
|
|
||||||
|
## Mistakes to Avoid
|
||||||
|
<!-- Failed approaches and why they failed -->
|
||||||
|
|
||||||
|
## Codebase Conventions
|
||||||
|
|
||||||
|
**[2026-05-04] — File organization**
|
||||||
|
- Observation: Most flashcard files are flat in `org/cpp/`, but subdirectories exist (`tricks/`, `dsa/`) for topic grouping. AGENTS.md only documents the flat convention.
|
||||||
|
- Action: When creating new cards, use flat `org/cpp/topic.org` for STL/language features; subdirectories for broader categories (DSA, tricks). Propose updating AGENTS.md if this solidifies.
|
||||||
|
- Confidence: medium
|
||||||
|
|
||||||
|
**[2026-05-04] — Card format variance**
|
||||||
|
- Observation: `org/cpp/dsa/udfs.org` uses raw `#+title:` + code blocks without ANKI properties. `org/cpp/ufds.org` follows the proper Anki card format. The proper format (with ANKI_NOTE_TYPE, Front/Back sections) is what gets exported.
|
||||||
|
- Action: Always use the full Anki card format from AGENTS.md when creating flashcards. Raw code files in dsa/ may be scratch/reference, not export-ready cards.
|
||||||
|
- Confidence: medium
|
||||||
|
|
||||||
|
**[2026-05-04] — Naming: UFDS not UDFS**
|
||||||
|
- Observation: `org/cpp/dsa/udfs.org` is a typo — the data structure is "Union-Find Disjoint Set" = UFDS. The properly-formatted file `org/cpp/ufds.org` uses the correct name.
|
||||||
|
- Action: Use "ufds" spelling. The dsa/udfs.org appears to be an earlier draft.
|
||||||
|
- Confidence: high
|
||||||
|
|
||||||
|
## Environment & Config
|
||||||
|
|
||||||
|
**[2026-05-04] — Git state**
|
||||||
|
- Observation: Single branch `master` with remote `origin/master`. No branching workflow — commits go directly to master.
|
||||||
|
- Action: Commit directly to master. Push when work is complete.
|
||||||
|
- Confidence: high
|
||||||
|
|
||||||
|
## Business Context
|
||||||
|
|
||||||
|
**[2026-05-04] — Study focus**
|
||||||
|
- Observation: Recent commits cover STL containers (deque, array, set, map, iterators) and DSA (UFDS). Inbox has LeetCode solutions (two sum, max consecutive ones) with notes to learn binary search and `using` keyword.
|
||||||
|
- Action: Current study trajectory is STL containers + competitive programming DSA. Prioritize cards for these topics.
|
||||||
|
- Confidence: high
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
|
||||||
|
**[2026-05-04] — Duplicate UFDS files**
|
||||||
|
- Question: Are both `org/cpp/ufds.org` (402 lines, proper format) and `org/cpp/dsa/udfs.org` (41 lines, raw code) needed? The former seems to supersede the latter.
|
||||||
|
- Action: Ask user if `dsa/udfs.org` should be removed or merged.
|
||||||
@@ -57,3 +57,43 @@ what is using?
|
|||||||
we need to write binary search, lower bound search
|
we need to write binary search, lower bound search
|
||||||
|
|
||||||
learn about binary search functions the natural one by god
|
learn about binary search functions the natural one by god
|
||||||
|
|
||||||
|
|
||||||
|
keep
|
||||||
|
#+begin_src c++
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int findMaxConsecutiveOnes(vector<int>& nums) {
|
||||||
|
bool state = false;
|
||||||
|
int prev = 0;
|
||||||
|
int best = 0;
|
||||||
|
nums.push_back(0);
|
||||||
|
for (int i=0; i<nums.size(); i++) {
|
||||||
|
if (!state && nums[i]==1) {
|
||||||
|
prev = i;
|
||||||
|
state = true;
|
||||||
|
} else if (state && nums[i]==0) {
|
||||||
|
best = std::max(best, i-prev);
|
||||||
|
state = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
* TODO study: why min doesn't work with Fenwick tree (no inverse, update breaks on increase)
|
||||||
|
|
||||||
|
* Binary search
|
||||||
|
#+begin_src python
|
||||||
|
def bs(a, x, l, r):
|
||||||
|
if l >= r:
|
||||||
|
return l
|
||||||
|
|
||||||
|
m = l + (r-l) // 2
|
||||||
|
if (a[m] < x):
|
||||||
|
return bs(a, x, m+1, r);
|
||||||
|
else:
|
||||||
|
return bs(a, x, l, m)
|
||||||
|
#+end_src
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
.cache/
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
# AGENTS.md — leetcode/
|
||||||
|
|
||||||
|
## What This Is
|
||||||
|
|
||||||
|
An idempotent extractor that pulls the NeetCode roadmap dependency graph
|
||||||
|
and problem list from the live site (neetcode.io). Outputs structured
|
||||||
|
JSON, Graphviz DOT, and Emacs org-mode files.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
NeetCode is an Angular SPA. The data we need is split across lazy-loaded
|
||||||
|
JS chunks:
|
||||||
|
|
||||||
|
1. **HTML** (`/roadmap`) — contains the `<script>` tags pointing to the
|
||||||
|
runtime and main bundle filenames (content-hashed).
|
||||||
|
2. **Runtime JS** — maps chunk IDs to content hashes:
|
||||||
|
`7669:"fc6133d290d8d0ad"`.
|
||||||
|
3. **Main bundle** (`main.*.js`) — contains all ~965 problems with
|
||||||
|
fields: `problem`, `pattern`, `link`, `difficulty`, `code`, flags
|
||||||
|
(`neetcode150`, `blind75`, `neetcode250`, `premium`).
|
||||||
|
4. **Chunk 7669** — contains the **graph nodes** (`id`, `name`,
|
||||||
|
`parentId[]`) and course-to-topic mappings. The `parentId` array
|
||||||
|
is the edge list — each entry points to a prerequisite topic.
|
||||||
|
|
||||||
|
The script (`extract.mjs`) resolves the hashed filenames at runtime,
|
||||||
|
downloads the chunks, and regex-extracts the data structures.
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node extract.mjs # writes to ./out/ + org/study_deck_02/roadmap.org
|
||||||
|
node extract.mjs --stdout # prints full JSON to stdout
|
||||||
|
node extract.mjs --cache /tmp/nc # custom cache directory
|
||||||
|
node scaffold-notes.mjs # create missing note files (skips existing)
|
||||||
|
node populate-notes.mjs # fill notes with descriptions + code stubs
|
||||||
|
node populate-notes.mjs --force # overwrite existing content
|
||||||
|
node populate-notes.mjs --dry-run # show what would change
|
||||||
|
```
|
||||||
|
|
||||||
|
Downloads are cached in `.cache/` (gitignored). Re-runs are instant
|
||||||
|
and produce byte-identical output.
|
||||||
|
|
||||||
|
## Scripts
|
||||||
|
|
||||||
|
| Script | Purpose |
|
||||||
|
|--------|---------|
|
||||||
|
| `extract.mjs` | Fetch NeetCode data, write JSON/DOT/org files |
|
||||||
|
| `scaffold-notes.mjs` | Create empty note files for each problem |
|
||||||
|
| `populate-notes.mjs` | Fetch problem descriptions + code stubs from LeetCode API |
|
||||||
|
|
||||||
|
## Output Files
|
||||||
|
|
||||||
|
| File | Contents |
|
||||||
|
|------|----------|
|
||||||
|
| `out/roadmap.json` | Full data: graph, all 965 problems, courses |
|
||||||
|
| `out/roadmap-neetcode150.json` | NeetCode 150 only (199 problems) |
|
||||||
|
| `out/roadmap.dot` | Graphviz DOT (render with `dot -Tsvg`) |
|
||||||
|
| `out/roadmap.org` | Org-mode with `TODO` checklists, Python/C++ links (moved to `org/study_deck_02/roadmap.org`) |
|
||||||
|
| `neetcode-roadmap-graph.json` | Standalone edge list (manual copy) |
|
||||||
|
| `neetcode-roadmap.dot` | Standalone DOT (manual copy) |
|
||||||
|
|
||||||
|
## The Dependency Graph
|
||||||
|
|
||||||
|
18 topics, 21 edges, topologically ordered:
|
||||||
|
|
||||||
|
```
|
||||||
|
Arrays & Hashing
|
||||||
|
├── Two Pointers
|
||||||
|
│ ├── Sliding Window
|
||||||
|
│ ├── Linked List → Trees
|
||||||
|
│ └── Binary Search → Trees
|
||||||
|
│ ├── Tries
|
||||||
|
│ ├── Heap / Priority Queue → Intervals, Greedy, Advanced Graphs
|
||||||
|
│ └── Backtracking
|
||||||
|
│ ├── Graphs → Advanced Graphs, 2-D DP, Math & Geometry
|
||||||
|
│ └── 1-D Dynamic Programming → 2-D DP, Bit Manipulation
|
||||||
|
└── Stack
|
||||||
|
```
|
||||||
|
|
||||||
|
## Org-Mode Format
|
||||||
|
|
||||||
|
Each topic is a `* TODO` heading with a `[/]` cookie for progress.
|
||||||
|
Problems are `** TODO` sub-headings with difficulty tags (`:easy:`,
|
||||||
|
`:medium:`, `:hard:`). Each problem has a properties drawer with links
|
||||||
|
to LeetCode, GitHub solutions (Python/C++), and video. A `Notes:` line
|
||||||
|
links to the personal notes file at
|
||||||
|
`org/study_deck_02/dsa/<topic>/<problem>.org`.
|
||||||
|
|
||||||
|
### Notes Files
|
||||||
|
|
||||||
|
`org/study_deck_02/dsa/<topic>/<code>.org` — one per NeetCode 150 problem (199 total).
|
||||||
|
Scaffolded by `scaffold-notes.mjs`. Template:
|
||||||
|
|
||||||
|
```org
|
||||||
|
* TODO 0217. Contains Duplicate :easy:
|
||||||
|
#+PROPERTY: STUDY_DECK_02
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0217. Contains Duplicate][Roadmap]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
#+begin_src cpp
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
```
|
||||||
|
|
||||||
|
Run `node scaffold-notes.mjs` to create missing note files (skips existing).
|
||||||
|
|
||||||
|
## Updating
|
||||||
|
|
||||||
|
Just re-run `node extract.mjs`. It fetches fresh data from the site
|
||||||
|
(cached locally). If NeetCode changes their chunk structure, the
|
||||||
|
regexes in `extractGraphNodes()` and `extractProblems()` will need
|
||||||
|
updating.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
None. Uses only Node.js built-ins (`fs`, `path`, `url`, `fetch`).
|
||||||
|
Requires Node 18+ for native `fetch`.
|
||||||
@@ -0,0 +1,372 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NeetCode Roadmap Extractor
|
||||||
|
*
|
||||||
|
* Fetches the NeetCode roadmap data (dependency graph + problems)
|
||||||
|
* from the live site and outputs structured JSON, DOT, and org-mode.
|
||||||
|
*
|
||||||
|
* Idempotent: same input always produces the same output.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* node extract.mjs # write to ./out/
|
||||||
|
* node extract.mjs --stdout # print JSON to stdout
|
||||||
|
* node extract.mjs --cache /tmp/nc # cache downloads in dir
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { writeFileSync, mkdirSync, readFileSync, existsSync } from "node:fs";
|
||||||
|
import { join, dirname } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
// ── Config ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
const BASE = "https://neetcode.io";
|
||||||
|
const ROADMAP_CHUNK_ID = 8998; // exports ROADMAP_ROUTES
|
||||||
|
const GRAPH_DATA_CHUNK_ID = 7669; // contains the actual graph nodes
|
||||||
|
const LEETCODE_BASE = "https://leetcode.com/problems/";
|
||||||
|
const GITHUB_SOLUTIONS =
|
||||||
|
"https://github.com/neetcode-gh/leetcode/blob/main/";
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const stdoutMode = args.includes("--stdout");
|
||||||
|
const cacheDir = args.includes("--cache")
|
||||||
|
? args[args.indexOf("--cache") + 1]
|
||||||
|
: join(__dirname, ".cache");
|
||||||
|
const outDir = join(__dirname, "out");
|
||||||
|
|
||||||
|
// ── Fetch with optional disk cache ──────────────────────────────────────────
|
||||||
|
|
||||||
|
async function fetchText(url, cacheKey) {
|
||||||
|
const cachePath = join(cacheDir, cacheKey);
|
||||||
|
if (existsSync(cachePath)) {
|
||||||
|
return readFileSync(cachePath, "utf8");
|
||||||
|
}
|
||||||
|
const res = await fetch(url);
|
||||||
|
if (!res.ok) throw new Error(`Failed to fetch ${url}: ${res.status}`);
|
||||||
|
const text = await res.text();
|
||||||
|
mkdirSync(dirname(cachePath), { recursive: true });
|
||||||
|
writeFileSync(cachePath, text, "utf8");
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Step 1: Get chunk hashes from runtime ───────────────────────────────────
|
||||||
|
|
||||||
|
async function getChunkHashes() {
|
||||||
|
const html = await fetchText(`${BASE}/roadmap`, "roadmap.html");
|
||||||
|
const runtimeMatch = html.match(/src="(runtime\.[a-f0-9]+\.js)"/);
|
||||||
|
if (!runtimeMatch) throw new Error("Could not find runtime JS filename");
|
||||||
|
const runtimeName = runtimeMatch[1];
|
||||||
|
const runtime = await fetchText(`${BASE}/${runtimeName}`, runtimeName);
|
||||||
|
|
||||||
|
const hashes = {};
|
||||||
|
for (const id of [ROADMAP_CHUNK_ID, GRAPH_DATA_CHUNK_ID]) {
|
||||||
|
const m = runtime.match(new RegExp(`${id}:"([a-f0-9]+)"`));
|
||||||
|
if (!m) throw new Error(`Could not find hash for chunk ${id}`);
|
||||||
|
hashes[id] = m[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const mainMatch = html.match(/src="(main\.[a-f0-9]+\.js)"/);
|
||||||
|
if (!mainMatch) throw new Error("Could not find main JS filename");
|
||||||
|
hashes.main = mainMatch[1];
|
||||||
|
|
||||||
|
return hashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Step 2: Extract graph nodes from chunk 7669 ─────────────────────────────
|
||||||
|
|
||||||
|
function extractGraphNodes(chunkSrc) {
|
||||||
|
const nodes = [];
|
||||||
|
const re =
|
||||||
|
/\{id:"(\d+)",name:"([^"]+)",backgroundColor:"([^"]+)"(?:,parentId:\[([^\]]*)\])?\}/g;
|
||||||
|
let m;
|
||||||
|
while ((m = re.exec(chunkSrc))) {
|
||||||
|
const [, id, name, , parentStr] = m;
|
||||||
|
const parents = parentStr
|
||||||
|
? parentStr
|
||||||
|
.split(",")
|
||||||
|
.map((s) => s.replace(/"/g, "").trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
: [];
|
||||||
|
nodes.push({ id, name, prerequisites: parents });
|
||||||
|
}
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Step 3: Extract problems from main bundle ───────────────────────────────
|
||||||
|
|
||||||
|
function extractProblems(mainSrc) {
|
||||||
|
const problems = [];
|
||||||
|
const re =
|
||||||
|
/\{problem:"([^"]+)",pattern:"([^"]+)",link:"([^"]+)",video:"([^"]*)",difficulty:"(\w+)",code:"([^"]+)"/g;
|
||||||
|
let m;
|
||||||
|
while ((m = re.exec(mainSrc))) {
|
||||||
|
const [, name, pattern, link, video, difficulty, code] = m;
|
||||||
|
const obj = { name, pattern, difficulty, code, link };
|
||||||
|
if (video) obj.video = video;
|
||||||
|
|
||||||
|
const ctxStart = Math.max(0, m.index - 50);
|
||||||
|
const ctxEnd = Math.min(mainSrc.length, m.index + m[0].length + 200);
|
||||||
|
const ctx = mainSrc.slice(ctxStart, ctxEnd);
|
||||||
|
if (/neetcode150:!0/.test(ctx)) obj.neetcode150 = true;
|
||||||
|
if (/blind75:!0/.test(ctx)) obj.blind75 = true;
|
||||||
|
if (/neetcode250:!0/.test(ctx)) obj.neetcode250 = true;
|
||||||
|
if (/premium:!0/.test(ctx)) obj.premium = true;
|
||||||
|
|
||||||
|
problems.push(obj);
|
||||||
|
}
|
||||||
|
return problems;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Step 4: Extract course links from chunk 7669 ────────────────────────────
|
||||||
|
|
||||||
|
function extractCourses(chunkSrc) {
|
||||||
|
const courses = {};
|
||||||
|
const re =
|
||||||
|
/"([^"]+)":\[\{course:"([^"]+)",name:"([^"]+)",routerLink:"([^"]+)"\}/g;
|
||||||
|
let m;
|
||||||
|
while ((m = re.exec(chunkSrc))) {
|
||||||
|
const topic = m[1];
|
||||||
|
const arrStart = m.index + topic.length + 2;
|
||||||
|
const arrEnd = chunkSrc.indexOf("]", arrStart);
|
||||||
|
const arrStr = chunkSrc.slice(arrStart, arrEnd + 1);
|
||||||
|
const items = [];
|
||||||
|
const itemRe =
|
||||||
|
/\{course:"([^"]+)",name:"([^"]+)",routerLink:"([^"]+)"\}/g;
|
||||||
|
let im;
|
||||||
|
while ((im = itemRe.exec(arrStr))) {
|
||||||
|
items.push({ course: im[1], name: im[2], routerLink: im[3] });
|
||||||
|
}
|
||||||
|
if (items.length) courses[topic] = items;
|
||||||
|
}
|
||||||
|
return courses;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Topological sort ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function topoSort(nodes) {
|
||||||
|
const byId = Object.fromEntries(nodes.map((n) => [n.id, n]));
|
||||||
|
const visited = new Set();
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
function visit(id) {
|
||||||
|
if (visited.has(id)) return;
|
||||||
|
visited.add(id);
|
||||||
|
const node = byId[id];
|
||||||
|
if (!node) return;
|
||||||
|
for (const p of node.prerequisites) visit(p);
|
||||||
|
result.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const n of nodes) visit(n.id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Build DOT graph ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function buildDot(nodes) {
|
||||||
|
const lines = [
|
||||||
|
"digraph NeetCodeRoadmap {",
|
||||||
|
' rankdir=TB;',
|
||||||
|
' node [shape=box, style="rounded,filled", fillcolor="#3f4bd1", fontcolor=white, fontname="Helvetica"];',
|
||||||
|
' edge [color="#555555", arrowsize=0.8];',
|
||||||
|
"",
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const n of nodes) {
|
||||||
|
const label = n.name.replace(/ \/ /g, "\\n").replace(/ /g, "\\n");
|
||||||
|
lines.push(` "${n.id}" [label="${label}"];`);
|
||||||
|
}
|
||||||
|
lines.push("");
|
||||||
|
|
||||||
|
for (const n of nodes) {
|
||||||
|
for (const p of n.prerequisites) {
|
||||||
|
lines.push(` "${p}" -> "${n.id}";`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push("}");
|
||||||
|
return lines.join("\n") + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Build org-mode file ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function buildOrg(sortedNodes, problemsByTopic) {
|
||||||
|
const lines = [];
|
||||||
|
const now = new Date().toISOString().slice(0, 10);
|
||||||
|
|
||||||
|
lines.push("#+TITLE: NeetCode Roadmap");
|
||||||
|
lines.push("#+PROPERTY: STUDY_DECK_02");
|
||||||
|
lines.push(`#+DATE: ${now}`);
|
||||||
|
lines.push("#+TODO: TODO DONE");
|
||||||
|
lines.push("#+STARTUP: overview");
|
||||||
|
lines.push("");
|
||||||
|
lines.push("Source: [[https://neetcode.io/roadmap][neetcode.io/roadmap]]");
|
||||||
|
lines.push("");
|
||||||
|
|
||||||
|
const difficultyTag = (d) =>
|
||||||
|
d === "Easy" ? "easy" : d === "Medium" ? "medium" : "hard";
|
||||||
|
|
||||||
|
const topicSlug = (name) =>
|
||||||
|
name
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, "-")
|
||||||
|
.replace(/(^-|-$)/g, "");
|
||||||
|
|
||||||
|
const notesRoot = "dsa";
|
||||||
|
|
||||||
|
for (const node of sortedNodes) {
|
||||||
|
const topicProblems = (problemsByTopic[node.name] || []).filter(
|
||||||
|
(p) => p.neetcode150
|
||||||
|
);
|
||||||
|
const slug = topicSlug(node.name);
|
||||||
|
lines.push(`* TODO ${node.name} [/]`);
|
||||||
|
lines.push("");
|
||||||
|
|
||||||
|
if (topicProblems.length === 0) {
|
||||||
|
lines.push(" (no NeetCode 150 problems)");
|
||||||
|
lines.push("");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const p of topicProblems) {
|
||||||
|
const tag = difficultyTag(p.difficulty);
|
||||||
|
const lcUrl = `${LEETCODE_BASE}${p.link}`;
|
||||||
|
const num = p.code.split("-")[0];
|
||||||
|
const notesFile = `${notesRoot}/${slug}/${p.code}.org`;
|
||||||
|
lines.push(`** TODO ${num}. ${p.name} :${tag}:`);
|
||||||
|
lines.push(`:PROPERTIES:`);
|
||||||
|
lines.push(`:LEETCODE: [[${lcUrl}][Problem]]`);
|
||||||
|
lines.push(`:CPP: [[${GITHUB_SOLUTIONS}cpp/${p.code}.cpp][Solution]]`);
|
||||||
|
lines.push(`:PYTHON: [[${GITHUB_SOLUTIONS}python/${p.code}.py][Solution]]`);
|
||||||
|
if (p.video)
|
||||||
|
lines.push(
|
||||||
|
`:VIDEO: [[https://youtube.com/watch?v=${p.video}][Watch]]`
|
||||||
|
);
|
||||||
|
lines.push(`:END:`);
|
||||||
|
lines.push("");
|
||||||
|
lines.push(`*** TODO Python`);
|
||||||
|
lines.push(`*** TODO C++`);
|
||||||
|
lines.push(`Notes: [[file:${notesFile}]]`);
|
||||||
|
}
|
||||||
|
lines.push("");
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Main ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const hashes = await getChunkHashes();
|
||||||
|
|
||||||
|
const [graphChunk, mainSrc] = await Promise.all([
|
||||||
|
fetchText(
|
||||||
|
`${BASE}/${GRAPH_DATA_CHUNK_ID}.${hashes[GRAPH_DATA_CHUNK_ID]}.js`,
|
||||||
|
`${GRAPH_DATA_CHUNK_ID}.${hashes[GRAPH_DATA_CHUNK_ID]}.js`
|
||||||
|
),
|
||||||
|
fetchText(`${BASE}/${hashes.main}`, hashes.main),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const nodes = extractGraphNodes(graphChunk);
|
||||||
|
const problems = extractProblems(mainSrc);
|
||||||
|
const courses = extractCourses(graphChunk);
|
||||||
|
|
||||||
|
// Build edges from prerequisites
|
||||||
|
const edges = [];
|
||||||
|
for (const n of nodes) {
|
||||||
|
for (const p of n.prerequisites) {
|
||||||
|
edges.push({ from: p, to: n.id, meaning: "prerequisite" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group problems by topic
|
||||||
|
const problemsByTopic = {};
|
||||||
|
for (const p of problems) {
|
||||||
|
if (!problemsByTopic[p.pattern]) problemsByTopic[p.pattern] = [];
|
||||||
|
problemsByTopic[p.pattern].push(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NeetCode 150 only
|
||||||
|
const nc150Problems = problems.filter((p) => p.neetcode150);
|
||||||
|
const nc150ByTopic = {};
|
||||||
|
for (const p of nc150Problems) {
|
||||||
|
if (!nc150ByTopic[p.pattern]) nc150ByTopic[p.pattern] = [];
|
||||||
|
nc150ByTopic[p.pattern].push(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Topological sort for org output
|
||||||
|
const sorted = topoSort(nodes);
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
source: "https://neetcode.io/roadmap",
|
||||||
|
extracted: new Date().toISOString().slice(0, 10),
|
||||||
|
graph: { nodes, edges },
|
||||||
|
problemsByTopic,
|
||||||
|
coursesByTopic: courses,
|
||||||
|
stats: {
|
||||||
|
topics: nodes.length,
|
||||||
|
edges: edges.length,
|
||||||
|
totalProblems: problems.length,
|
||||||
|
neetcode150: nc150Problems.length,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (stdoutMode) {
|
||||||
|
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
||||||
|
} else {
|
||||||
|
mkdirSync(outDir, { recursive: true });
|
||||||
|
|
||||||
|
// Full data
|
||||||
|
writeFileSync(
|
||||||
|
join(outDir, "roadmap.json"),
|
||||||
|
JSON.stringify(result, null, 2) + "\n",
|
||||||
|
"utf8"
|
||||||
|
);
|
||||||
|
|
||||||
|
// NeetCode 150 only
|
||||||
|
const nc150Result = {
|
||||||
|
source: result.source,
|
||||||
|
extracted: result.extracted,
|
||||||
|
graph: result.graph,
|
||||||
|
problemsByTopic: nc150ByTopic,
|
||||||
|
coursesByTopic: courses,
|
||||||
|
stats: {
|
||||||
|
topics: nodes.length,
|
||||||
|
edges: edges.length,
|
||||||
|
problems: nc150Problems.length,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
writeFileSync(
|
||||||
|
join(outDir, "roadmap-neetcode150.json"),
|
||||||
|
JSON.stringify(nc150Result, null, 2) + "\n",
|
||||||
|
"utf8"
|
||||||
|
);
|
||||||
|
|
||||||
|
// DOT
|
||||||
|
writeFileSync(join(outDir, "roadmap.dot"), buildDot(nodes), "utf8");
|
||||||
|
|
||||||
|
// Org-mode — write to org/study_deck_02/roadmap.org
|
||||||
|
const orgDir = join(__dirname, "../org/study_deck_02");
|
||||||
|
mkdirSync(orgDir, { recursive: true });
|
||||||
|
writeFileSync(
|
||||||
|
join(orgDir, "roadmap.org"),
|
||||||
|
buildOrg(sorted, problemsByTopic),
|
||||||
|
"utf8"
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`Wrote ${outDir}/roadmap.json (${result.stats.totalProblems} problems total)`);
|
||||||
|
console.log(`Wrote ${outDir}/roadmap-neetcode150.json (${result.stats.neetcode150} problems)`);
|
||||||
|
console.log(`Wrote ${outDir}/roadmap.dot`);
|
||||||
|
console.log(`Wrote ${join(orgDir, "roadmap.org")}`);
|
||||||
|
console.log(
|
||||||
|
` ${result.stats.topics} topics, ${result.stats.edges} edges`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"source": "https://neetcode.io/roadmap",
|
||||||
|
"extracted": "2026-06-01",
|
||||||
|
"nodes": [
|
||||||
|
{ "id": "1", "name": "Arrays & Hashing" },
|
||||||
|
{ "id": "2", "name": "Two Pointers" },
|
||||||
|
{ "id": "3", "name": "Stack" },
|
||||||
|
{ "id": "4", "name": "Sliding Window" },
|
||||||
|
{ "id": "5", "name": "Linked List" },
|
||||||
|
{ "id": "6", "name": "Binary Search" },
|
||||||
|
{ "id": "7", "name": "Trees" },
|
||||||
|
{ "id": "8", "name": "Tries" },
|
||||||
|
{ "id": "9", "name": "Heap / Priority Queue" },
|
||||||
|
{ "id": "10", "name": "Backtracking" },
|
||||||
|
{ "id": "11", "name": "Graphs" },
|
||||||
|
{ "id": "12", "name": "1-D Dynamic Programming" },
|
||||||
|
{ "id": "13", "name": "Intervals" },
|
||||||
|
{ "id": "14", "name": "2-D Dynamic Programming" },
|
||||||
|
{ "id": "15", "name": "Bit Manipulation" },
|
||||||
|
{ "id": "16", "name": "Greedy" },
|
||||||
|
{ "id": "17", "name": "Advanced Graphs" },
|
||||||
|
{ "id": "18", "name": "Math & Geometry" }
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{ "from": "1", "to": "2", "meaning": "prerequisite" },
|
||||||
|
{ "from": "1", "to": "3", "meaning": "prerequisite" },
|
||||||
|
{ "from": "2", "to": "4", "meaning": "prerequisite" },
|
||||||
|
{ "from": "2", "to": "5", "meaning": "prerequisite" },
|
||||||
|
{ "from": "2", "to": "6", "meaning": "prerequisite" },
|
||||||
|
{ "from": "5", "to": "7", "meaning": "prerequisite" },
|
||||||
|
{ "from": "6", "to": "7", "meaning": "prerequisite" },
|
||||||
|
{ "from": "7", "to": "8", "meaning": "prerequisite" },
|
||||||
|
{ "from": "7", "to": "9", "meaning": "prerequisite" },
|
||||||
|
{ "from": "7", "to": "10", "meaning": "prerequisite" },
|
||||||
|
{ "from": "10", "to": "11", "meaning": "prerequisite" },
|
||||||
|
{ "from": "10", "to": "12", "meaning": "prerequisite" },
|
||||||
|
{ "from": "9", "to": "13", "meaning": "prerequisite" },
|
||||||
|
{ "from": "9", "to": "16", "meaning": "prerequisite" },
|
||||||
|
{ "from": "9", "to": "17", "meaning": "prerequisite" },
|
||||||
|
{ "from": "11", "to": "14", "meaning": "prerequisite" },
|
||||||
|
{ "from": "11", "to": "17", "meaning": "prerequisite" },
|
||||||
|
{ "from": "11", "to": "18", "meaning": "prerequisite" },
|
||||||
|
{ "from": "12", "to": "14", "meaning": "prerequisite" },
|
||||||
|
{ "from": "12", "to": "15", "meaning": "prerequisite" },
|
||||||
|
{ "from": "15", "to": "18", "meaning": "prerequisite" }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// NeetCode Roadmap — Topic Dependency Graph
|
||||||
|
// Source: https://neetcode.io/roadmap (chunk 7669)
|
||||||
|
// Extracted: 2026-06-01
|
||||||
|
//
|
||||||
|
// Render: dot -Tpng neetcode-roadmap.dot -o neetcode-roadmap.png
|
||||||
|
// or: dot -Tsvg neetcode-roadmap.dot -o neetcode-roadmap.svg
|
||||||
|
|
||||||
|
digraph NeetCodeRoadmap {
|
||||||
|
rankdir=TB;
|
||||||
|
node [shape=box, style="rounded,filled", fillcolor="#3f4bd1", fontcolor=white, fontname="Helvetica"];
|
||||||
|
edge [color="#555555", arrowsize=0.8];
|
||||||
|
|
||||||
|
// Nodes
|
||||||
|
"1" [label="Arrays &\nHashing"];
|
||||||
|
"2" [label="Two Pointers"];
|
||||||
|
"3" [label="Stack"];
|
||||||
|
"4" [label="Sliding Window"];
|
||||||
|
"5" [label="Linked List"];
|
||||||
|
"6" [label="Binary Search"];
|
||||||
|
"7" [label="Trees"];
|
||||||
|
"8" [label="Tries"];
|
||||||
|
"9" [label="Heap /\nPriority Queue"];
|
||||||
|
"10" [label="Backtracking"];
|
||||||
|
"11" [label="Graphs"];
|
||||||
|
"12" [label="1-D Dynamic\nProgramming"];
|
||||||
|
"13" [label="Intervals"];
|
||||||
|
"14" [label="2-D Dynamic\nProgramming"];
|
||||||
|
"15" [label="Bit Manipulation"];
|
||||||
|
"16" [label="Greedy"];
|
||||||
|
"17" [label="Advanced Graphs"];
|
||||||
|
"18" [label="Math &\nGeometry"];
|
||||||
|
|
||||||
|
// Edges (parentId → node means "parentId is a prerequisite of node")
|
||||||
|
"1" -> "2";
|
||||||
|
"1" -> "3";
|
||||||
|
"2" -> "4";
|
||||||
|
"2" -> "5";
|
||||||
|
"2" -> "6";
|
||||||
|
"5" -> "7";
|
||||||
|
"6" -> "7";
|
||||||
|
"7" -> "8";
|
||||||
|
"7" -> "9";
|
||||||
|
"7" -> "10";
|
||||||
|
"10" -> "11";
|
||||||
|
"10" -> "12";
|
||||||
|
"9" -> "13";
|
||||||
|
"9" -> "16";
|
||||||
|
"9" -> "17";
|
||||||
|
"11" -> "14";
|
||||||
|
"11" -> "17";
|
||||||
|
"11" -> "18";
|
||||||
|
"12" -> "14";
|
||||||
|
"12" -> "15";
|
||||||
|
"15" -> "18";
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
|||||||
|
digraph NeetCodeRoadmap {
|
||||||
|
rankdir=TB;
|
||||||
|
node [shape=box, style="rounded,filled", fillcolor="#3f4bd1", fontcolor=white, fontname="Helvetica"];
|
||||||
|
edge [color="#555555", arrowsize=0.8];
|
||||||
|
|
||||||
|
"1" [label="Arrays\n&\nHashing"];
|
||||||
|
"2" [label="Two\nPointers"];
|
||||||
|
"6" [label="Binary\nSearch"];
|
||||||
|
"3" [label="Stack"];
|
||||||
|
"4" [label="Sliding\nWindow"];
|
||||||
|
"5" [label="Linked\nList"];
|
||||||
|
"7" [label="Trees"];
|
||||||
|
"8" [label="Tries"];
|
||||||
|
"9" [label="Heap\nPriority\nQueue"];
|
||||||
|
"10" [label="Backtracking"];
|
||||||
|
"11" [label="Graphs"];
|
||||||
|
"12" [label="1-D\nDynamic\nProgramming"];
|
||||||
|
"13" [label="Intervals"];
|
||||||
|
"16" [label="Greedy"];
|
||||||
|
"17" [label="Advanced\nGraphs"];
|
||||||
|
"18" [label="Math\n&\nGeometry"];
|
||||||
|
"14" [label="2-D\nDynamic\nProgramming"];
|
||||||
|
"15" [label="Bit\nManipulation"];
|
||||||
|
|
||||||
|
"1" -> "2";
|
||||||
|
"2" -> "6";
|
||||||
|
"1" -> "3";
|
||||||
|
"2" -> "4";
|
||||||
|
"2" -> "5";
|
||||||
|
"5" -> "7";
|
||||||
|
"6" -> "7";
|
||||||
|
"7" -> "8";
|
||||||
|
"7" -> "9";
|
||||||
|
"7" -> "10";
|
||||||
|
"10" -> "11";
|
||||||
|
"10" -> "12";
|
||||||
|
"9" -> "13";
|
||||||
|
"9" -> "16";
|
||||||
|
"9" -> "17";
|
||||||
|
"11" -> "17";
|
||||||
|
"11" -> "18";
|
||||||
|
"15" -> "18";
|
||||||
|
"11" -> "14";
|
||||||
|
"12" -> "14";
|
||||||
|
"12" -> "15";
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,277 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate DSA note files with problem descriptions and code stubs
|
||||||
|
* from LeetCode's GraphQL API.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* node populate-notes.mjs # populate all missing
|
||||||
|
* node populate-notes.mjs --force # overwrite existing content
|
||||||
|
* node populate-notes.mjs --dry-run # show what would change
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
readFileSync,
|
||||||
|
writeFileSync,
|
||||||
|
existsSync,
|
||||||
|
mkdirSync,
|
||||||
|
} from "node:fs";
|
||||||
|
import { join, dirname } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const force = args.includes("--force");
|
||||||
|
const dryRun = args.includes("--dry-run");
|
||||||
|
|
||||||
|
const roadmap = JSON.parse(
|
||||||
|
readFileSync(join(__dirname, "out/roadmap.json"), "utf8")
|
||||||
|
);
|
||||||
|
const dsaDir = join(__dirname, "../org/study_deck_02/dsa");
|
||||||
|
const cacheDir = join(__dirname, ".cache/leetcode");
|
||||||
|
mkdirSync(cacheDir, { recursive: true });
|
||||||
|
|
||||||
|
const API = "https://leetcode.com/graphql";
|
||||||
|
const DELAY_MS = 300;
|
||||||
|
|
||||||
|
const topicSlug = (name) =>
|
||||||
|
name
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, "-")
|
||||||
|
.replace(/(^-|-$)/g, "");
|
||||||
|
|
||||||
|
function sleep(ms) {
|
||||||
|
return new Promise((r) => setTimeout(r, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchProblem(titleSlug) {
|
||||||
|
const cachePath = join(cacheDir, `${titleSlug}.json`);
|
||||||
|
if (existsSync(cachePath)) {
|
||||||
|
return JSON.parse(readFileSync(cachePath, "utf8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(API, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
query: `query {
|
||||||
|
question(titleSlug: "${titleSlug}") {
|
||||||
|
title
|
||||||
|
content
|
||||||
|
difficulty
|
||||||
|
codeSnippets { lang langSlug code }
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
console.error(` HTTP ${res.status} for ${titleSlug}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
const q = data?.data?.question;
|
||||||
|
if (!q) {
|
||||||
|
console.error(` No data for ${titleSlug}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFileSync(cachePath, JSON.stringify(q, null, 2), "utf8");
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
function htmlToOrg(html) {
|
||||||
|
if (!html) return "";
|
||||||
|
|
||||||
|
let text = html;
|
||||||
|
|
||||||
|
// Preserve code blocks
|
||||||
|
const codeBlocks = [];
|
||||||
|
text = text.replace(
|
||||||
|
/<pre>([\s\S]*?)<\/pre>/g,
|
||||||
|
(_, code) => {
|
||||||
|
const cleaned = code
|
||||||
|
.replace(/<[^>]+>/g, "")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/ /g, " ")
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.trim();
|
||||||
|
codeBlocks.push(cleaned);
|
||||||
|
return `__CODE_BLOCK_${codeBlocks.length - 1}__`;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Inline code
|
||||||
|
text = text.replace(/<code>([\s\S]*?)<\/code>/g, "~$1~");
|
||||||
|
|
||||||
|
// Bold
|
||||||
|
text = text.replace(/<strong[^>]*>([\s\S]*?)<\/strong>/g, "*$1*");
|
||||||
|
|
||||||
|
// Italic
|
||||||
|
text = text.replace(/<em>([\s\S]*?)<\/em>/g, "/$1/");
|
||||||
|
|
||||||
|
// Line breaks and paragraphs
|
||||||
|
text = text.replace(/<br\s*\/?>/g, "\n");
|
||||||
|
text = text.replace(/<\/p>/g, "\n");
|
||||||
|
text = text.replace(/<p[^>]*>/g, "");
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
text = text.replace(/<li[^>]*>/g, "- ");
|
||||||
|
text = text.replace(/<\/li>/g, "\n");
|
||||||
|
text = text.replace(/<\/?[ou]l[^>]*>/g, "");
|
||||||
|
|
||||||
|
// Sup/sub
|
||||||
|
text = text.replace(/<sup>([\s\S]*?)<\/sup>/g, "^{$1}");
|
||||||
|
text = text.replace(/<sub>([\s\S]*?)<\/sub>/g, "_{$1}");
|
||||||
|
|
||||||
|
// Example blocks — flatten to plain text
|
||||||
|
text = text.replace(
|
||||||
|
/<div class="example-block">([\s\S]*?)<\/div>/g,
|
||||||
|
(_, inner) => inner.replace(/<[^>]+>/g, "").trim() + "\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Strip remaining HTML tags
|
||||||
|
text = text.replace(/<[^>]+>/g, "");
|
||||||
|
|
||||||
|
// Decode HTML entities
|
||||||
|
text = text.replace(/</g, "<");
|
||||||
|
text = text.replace(/>/g, ">");
|
||||||
|
text = text.replace(/&/g, "&");
|
||||||
|
text = text.replace(/ /g, " ");
|
||||||
|
text = text.replace(/"/g, '"');
|
||||||
|
text = text.replace(/'/g, "'");
|
||||||
|
|
||||||
|
// Collapse whitespace but preserve intentional newlines
|
||||||
|
text = text.replace(/[ \t]+/g, " ");
|
||||||
|
text = text.replace(/\n\s*\n\s*\n+/g, "\n\n");
|
||||||
|
text = text.trim();
|
||||||
|
|
||||||
|
// Restore code blocks
|
||||||
|
for (let i = 0; i < codeBlocks.length; i++) {
|
||||||
|
text = text.replace(
|
||||||
|
`__CODE_BLOCK_${i}__`,
|
||||||
|
`\n#+begin_src\n${codeBlocks[i]}\n#+end_src\n`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildNoteContent(num, name, diff, description, stubs, relPath) {
|
||||||
|
const py = stubs.find((s) => s.langSlug === "python3");
|
||||||
|
const cpp = stubs.find((s) => s.langSlug === "cpp");
|
||||||
|
|
||||||
|
let out = `#+PROPERTY: STUDY_DECK_02
|
||||||
|
* TODO ${num}. ${name} :${diff}:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:${relPath}][${num}. ${name}]]
|
||||||
|
:END:
|
||||||
|
`;
|
||||||
|
|
||||||
|
if (description) {
|
||||||
|
out += `\n${description}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
out += `
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python
|
||||||
|
${py ? py.code.trim() : ""}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp
|
||||||
|
${cpp ? cpp.code.trim() : ""}
|
||||||
|
#+end_src
|
||||||
|
`;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Main ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const allProblems = [];
|
||||||
|
for (const [topic, problems] of Object.entries(roadmap.problemsByTopic)) {
|
||||||
|
for (const p of problems) {
|
||||||
|
if (p.neetcode150) {
|
||||||
|
allProblems.push({ ...p, topicSlug: topicSlug(topic) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Processing ${allProblems.length} NeetCode 150 problems...`);
|
||||||
|
if (dryRun) console.log("(dry run — no files written)\n");
|
||||||
|
|
||||||
|
let populated = 0;
|
||||||
|
let skipped = 0;
|
||||||
|
let errors = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < allProblems.length; i++) {
|
||||||
|
const p = allProblems[i];
|
||||||
|
const titleSlug = p.link.replace(/\/$/, "");
|
||||||
|
const filePath = join(dsaDir, p.topicSlug, `${p.code}.org`);
|
||||||
|
|
||||||
|
process.stdout.write(`[${i + 1}/${allProblems.length}] ${p.code}...`);
|
||||||
|
|
||||||
|
if (!existsSync(filePath)) {
|
||||||
|
console.log(" SKIP (no note file)");
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const existing = readFileSync(filePath, "utf8");
|
||||||
|
const hasDescription = existing.includes("** TODO Approach\nWrite your approach here.") === false ||
|
||||||
|
existing.split("\n").filter(l => l.trim() && !l.startsWith("#") && !l.startsWith(":") && !l.startsWith("*") && !l.startsWith("**") && !l.startsWith("-") && !l.startsWith("Write your approach")).length > 10;
|
||||||
|
|
||||||
|
if (!force && hasDescription && !existing.includes("Write your approach here.")) {
|
||||||
|
console.log(" SKIP (already populated)");
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const question = await fetchProblem(titleSlug);
|
||||||
|
if (!question) {
|
||||||
|
console.log(" ERROR");
|
||||||
|
errors++;
|
||||||
|
await sleep(DELAY_MS);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const description = htmlToOrg(question.content);
|
||||||
|
const stubs = question.codeSnippets || [];
|
||||||
|
const num = p.code.split("-")[0];
|
||||||
|
const relPath = `../../roadmap.org::*${num}. ${p.name}`;
|
||||||
|
|
||||||
|
const content = buildNoteContent(
|
||||||
|
num,
|
||||||
|
p.name,
|
||||||
|
p.difficulty.toLowerCase(),
|
||||||
|
description,
|
||||||
|
stubs,
|
||||||
|
relPath
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!dryRun) {
|
||||||
|
writeFileSync(filePath, content, "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(` OK (${description.length} chars)`);
|
||||||
|
populated++;
|
||||||
|
|
||||||
|
await sleep(DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\nDone: ${populated} populated, ${skipped} skipped, ${errors} errors`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
||||||
|
import { join, dirname } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
const roadmap = readFileSync(join(__dirname, "../org/study_deck_02/roadmap.org"), "utf8");
|
||||||
|
const dsaDir = join(__dirname, "../org/study_deck_02/dsa");
|
||||||
|
|
||||||
|
const topicSlug = (name) =>
|
||||||
|
name
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, "-")
|
||||||
|
.replace(/(^-|-$)/g, "");
|
||||||
|
|
||||||
|
let currentTopic = "";
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
for (const line of roadmap.split("\n")) {
|
||||||
|
const topicMatch = line.match(/^\* TODO (.+?) \[/);
|
||||||
|
if (topicMatch) {
|
||||||
|
currentTopic = topicSlug(topicMatch[1]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const problemMatch = line.match(
|
||||||
|
/^\*\* TODO (\d+)\. (.+?) :(easy|medium|hard):/
|
||||||
|
);
|
||||||
|
if (problemMatch) {
|
||||||
|
const [, num, name, diff] = problemMatch;
|
||||||
|
const slug = name
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, "-")
|
||||||
|
.replace(/(^-|-$)/g, "");
|
||||||
|
const code = `${num}-${slug}`;
|
||||||
|
const filePath = join(dsaDir, currentTopic, `${code}.org`);
|
||||||
|
|
||||||
|
if (existsSync(filePath)) continue;
|
||||||
|
|
||||||
|
const relPath = `../../roadmap.org::*${num}. ${name}`;
|
||||||
|
const content = `#+PROPERTY: STUDY_DECK_02
|
||||||
|
* TODO ${num}. ${name} :${diff}:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:${relPath}][Roadmap]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
`;
|
||||||
|
writeFileSync(filePath, content);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Created ${count} note files`);
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
* Why can't you return a raw C-style array :cpp:arrays:elaborative-why:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1776793508138
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Why is returning a raw C-style array illegal in C++?
|
||||||
|
** Back
|
||||||
|
Arrays /decay to pointers/ when passed around. Returning one would return a pointer to a local variable that's destroyed when the function returns — undefined behavior. The compiler forbids it.
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
int arr[26];
|
||||||
|
return arr; // ❌ returns pointer to dead stack memory
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* std::array vs int[]: key differences :cpp:arrays:comparative:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1776793508134
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
How does ~std::array<int, 26>~ differ from ~int[26]~?
|
||||||
|
** Back
|
||||||
|
| Feature | ~int[26]~ | ~std::array<int,26>~ |
|
||||||
|
|----------------------+---------+--------------------|
|
||||||
|
| Return by value | No | Yes |
|
||||||
|
| Copy/assign | No | Yes |
|
||||||
|
| Knows its own size | No | ~.size()~ |
|
||||||
|
| Works with STL algos | No | Yes |
|
||||||
|
| Zero-init with ~{}~ | No | Yes |
|
||||||
|
|
||||||
|
Same machine code — zero overhead.
|
||||||
|
|
||||||
|
* Task: return character frequency count from string :cpp:arrays:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1776793508129
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write a function that counts character frequencies in a string and returns the result. The string has only lowercase letters.
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::array<int, 26> calc(const std::string& str) {
|
||||||
|
std::array<int, 26> arr{};
|
||||||
|
for (char c : str) {
|
||||||
|
arr[c - 'a']++;
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Stack vs heap: std::array vs std::vector :cpp:arrays:comparative:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1776793508124
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Where is the data stored for ~std::array<int,26>~ vs ~std::vector<int>(26)~?
|
||||||
|
** Back
|
||||||
|
- ~std::array~ → *stack*. Data stored inline inside the struct, no dynamic allocation.
|
||||||
|
- ~std::vector~ → *heap*. Internally calls ~new[]~, pointer indirection.
|
||||||
|
|
||||||
|
Rule: use ~std::array~ when size is known at compile time (fast, no alloc). Use ~std::vector~ when size is dynamic.
|
||||||
|
|
||||||
|
* Why const in const T& parameter :cpp:references:elaborative-why:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1776793508119
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Why write ~const std::string&~ instead of ~std::string&~ for a read-only parameter?
|
||||||
|
** Back
|
||||||
|
Two reasons:
|
||||||
|
|
||||||
|
1. *Enforces intent* — compiler catches accidental mutation inside the function.
|
||||||
|
2. *Allows more callers* — without ~const~, you can't pass temporaries or const variables:
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
calc("hello"); // ❌ without const
|
||||||
|
const std::string s = "hi";
|
||||||
|
calc(s); // ❌ without const
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Why & instead of pass-by-value for string param :cpp:references:elaborative-why:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1776793508114
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Why pass ~std::string~ by reference (~const std::string&~) instead of by value?
|
||||||
|
** Back
|
||||||
|
~std::string~ contains a heap allocation. Passing by value copies it — allocating memory and copying every character.
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
calc(std::string str) // copies entire string — heap allocation
|
||||||
|
calc(const std::string& str) // passes address only — no copy
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
For a function that only reads, the copy is pure waste.
|
||||||
|
|
||||||
|
* Reference vs pointer for function parameters :cpp:references:comparative:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1776793508109
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
When do you use ~T&~ vs ~T*~ for a function parameter?
|
||||||
|
** Back
|
||||||
|
| Feature | Reference ~T&~ | Pointer ~T*~ |
|
||||||
|
|-------------------+--------------+------------|
|
||||||
|
| Can be null | No | Yes |
|
||||||
|
| Dereference | ~str[i]~ | ~(*str)[i]~ |
|
||||||
|
| Can be reassigned | No | Yes |
|
||||||
|
|
||||||
|
Use ~T*~ when null is a valid input. Use ~T&~ when the value is *guaranteed to exist* — which is almost always the case for function parameters.
|
||||||
|
|
||||||
|
* Rule of thumb: C++ function parameter types :cpp:references:factual:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1776793508102
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What's the general rule for choosing parameter types in C++ functions?
|
||||||
|
** Back
|
||||||
|
- *Non-trivial types* (~string~, ~vector~, structs): use ~const T&~ for read-only, ~T&~ for mutating
|
||||||
|
- *Cheap types* (~int~, ~char~, ~bool~, pointers): pass by value
|
||||||
|
- *Nullable input*: use ~T*~
|
||||||
|
- *Guaranteed non-null*: use ~T&~
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
#+title: C++ Containers
|
||||||
|
|
||||||
|
* Container Concept: Common Interface :containers:concept:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 20260504002
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What interface is shared by all C++ standard containers?
|
||||||
|
** Back
|
||||||
|
- *Element access*: ~at~, ~operator[]~, ~front~, ~back~, ~data~
|
||||||
|
- *Iterators*: ~begin~, ~end~, ~cbegin~, ~cend~, ~rbegin~, ~rend~
|
||||||
|
- *Capacity*: ~empty~, ~size~, ~max_size~
|
||||||
|
- *Modifiers*: ~clear~, ~insert~, ~erase~, ~push_back~, ~pop_back~, ~resize~, ~swap~
|
||||||
|
|
||||||
|
* Do C++ containers inherit from a common base? :containers:concept:inheritance:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 20260504003
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Do C++ containers (vector, list, map, etc.) inherit from a common base class?
|
||||||
|
** Back
|
||||||
|
No. Standard containers are standalone classes. Shared interfaces come from conventions and C++20 concepts (~Container~, ~SequenceContainer~), not inheritance.
|
||||||
|
|
||||||
|
* Sequence Containers :containers:sequence:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 20260504004
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What are the C++ sequence containers?
|
||||||
|
** Back
|
||||||
|
~vector~, ~deque~, ~list~, ~forward_list~, ~array~
|
||||||
|
|
||||||
|
Sequence containers maintain insertion order.
|
||||||
|
|
||||||
|
* Associative Containers :containers:associative:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 20260504005
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What are the C++ associative containers?
|
||||||
|
** Back
|
||||||
|
- *Ordered*: ~set~, ~multiset~, ~map~, ~multimap~
|
||||||
|
- *Unordered*: ~unordered_set~, ~unordered_multiset~, ~unordered_map~, ~unordered_multimap~
|
||||||
|
|
||||||
|
* Container Adapters :containers:adapter:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_ID: 1777826871054
|
||||||
|
:END:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 20260504006
|
||||||
|
** Front
|
||||||
|
What are the C++ container adapters?
|
||||||
|
** Back
|
||||||
|
~stack~, ~queue~, ~priority_queue~
|
||||||
|
|
||||||
|
Adapters provide a restricted interface (e.g., LIFO for stack, FIFO for queue).
|
||||||
|
|
||||||
|
* What does vector have that other containers don't? :containers:vector:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 20260504007
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Which methods does ~vector~ have that other containers typically don't?
|
||||||
|
** Back
|
||||||
|
~reserve~, ~capacity~, ~shrink_to_fit~
|
||||||
|
|
||||||
|
These manage the internal memory buffer.
|
||||||
|
|
||||||
|
* Unique methods on sequence containers (list, deque) :containers:sequence:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 20260504008
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Which sequence containers support ~push_front~ and ~pop_front~?
|
||||||
|
** Back
|
||||||
|
~deque~ and ~list~ (not ~vector~)
|
||||||
|
|
||||||
|
These containers support insertion/removal at both ends.
|
||||||
|
|
||||||
|
* Unique methods on associative containers :containers:associative:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 20260504009
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What tree-based methods do ordered associative containers have?
|
||||||
|
** Back
|
||||||
|
~find~, ~count~, ~lower_bound~, ~upper_bound~, ~equal_range~
|
||||||
|
|
||||||
|
These use tree traversal (BST behind the scenes).
|
||||||
|
|
||||||
|
* Unique methods on unordered containers :containers:unordered:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 20260504010
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What hash-specific methods do unordered containers have?
|
||||||
|
** Back
|
||||||
|
~bucket_count~, ~load_factor~, ~max_load_factor~, ~rehash~, ~reserve~
|
||||||
|
|
||||||
|
These manage hash table internals.
|
||||||
@@ -0,0 +1,396 @@
|
|||||||
|
* Task: construct an empty deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650432
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to create an empty deque of ints
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d;
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: construct deque with 5 copies of value :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650427
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to create a deque with 5 elements, all initialized to 42
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d(5, 42); // {42, 42, 42, 42, 42}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: construct deque from initializer list :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650422
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to create a deque initialized with {1, 2, 3}
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: construct deque from a range :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650418
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to create a deque from a vector's begin/end iterators
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::vector<int> v = {1, 2, 3, 4, 5};
|
||||||
|
std::deque<int> d(v.begin(), v.end());
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: access element at index with bounds checking :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650414
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to safely access element at index 2 in a deque (throws on invalid index)
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {10, 20, 30};
|
||||||
|
int x = d.at(2); // returns 30, throws std::out_of_range if invalid
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: access element at index with operator[] :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650409
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to access element at index 1 using operator[]
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {10, 20, 30};
|
||||||
|
int x = d[1]; // returns 20, no bounds check
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: access first and last elements :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650404
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to get the first and last element of a deque
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {10, 20, 30};
|
||||||
|
int first = d.front(); // 10
|
||||||
|
int last = d.back(); // 30
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: iterate over deque with begin/end :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650399
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write a range-based for loop over a deque using iterators
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
for (auto it = d.begin(); it != d.end(); ++it) {
|
||||||
|
std::cout << *it << " ";
|
||||||
|
}
|
||||||
|
// or:
|
||||||
|
for (int x : d) { std::cout << x << " "; }
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: reverse iterate over deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650395
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to iterate backwards through a deque using reverse iterators
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
for (auto it = d.rbegin(); it != d.rend(); ++it) {
|
||||||
|
std::cout << *it << " "; // prints 3 2 1
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: check if deque is empty :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650391
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to check if a deque is empty
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d;
|
||||||
|
if (d.empty()) { /* ... */ }
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: get size of deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650387
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to get the number of elements in a deque
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
std::size_t n = d.size(); // returns 3
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: clear all elements from deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650383
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to remove all elements from a deque
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
d.clear(); // size becomes 0
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: push elements to back of deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650379
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to add elements 10, 20, 30 to the back of a deque
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d;
|
||||||
|
d.push_back(10);
|
||||||
|
d.push_back(20);
|
||||||
|
d.push_back(30);
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: push elements to front of deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650375
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to add elements 30, 20, 10 to the front of a deque (pushing in that order)
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d;
|
||||||
|
d.push_front(30); // {30}
|
||||||
|
d.push_front(20); // {20, 30}
|
||||||
|
d.push_front(10); // {10, 20, 30}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: pop elements from back of deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650371
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to remove the last element from a deque
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
d.pop_back(); // {1, 2}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: pop elements from front of deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650367
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to remove the first element from a deque
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
d.pop_front(); // {2, 3}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: emplace back into deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650363
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to construct a pair in-place at the back of a deque (without copying)
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<std::pair<int,int>> d;
|
||||||
|
d.emplace_back(1, 2); // constructs pair{1,2} directly
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: emplace front into deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650359
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to construct an element in-place at the front of a deque
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<std::string> d;
|
||||||
|
d.emplace_front("hello"); // constructs string directly at front
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: resize deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650354
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to resize a deque to 10 elements, filling new spots with 0
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
d.resize(10); // {1, 2, 3, 0, 0, 0, 0, 0, 0, 0}
|
||||||
|
d.resize(5, 42); // resize to 5, filling with 42 if growing
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: insert element at position :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650349
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to insert value 99 at the beginning of a deque
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
d.insert(d.begin(), 99); // {99, 1, 2, 3}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: insert multiple copies :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650344
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to insert 5 copies of value 42 starting at position begin
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
d.insert(d.begin(), 5, 42); // {42, 42, 42, 42, 42, 1, 2, 3}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: insert range into deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650339
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to insert all elements from a vector into a deque at position begin
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
std::vector<int> v = {10, 20};
|
||||||
|
d.insert(d.begin(), v.begin(), v.end()); // {10, 20, 1, 2, 3}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: erase single element :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650335
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to erase the element at position begin + 1 in a deque
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
d.erase(d.begin() + 1); // {1, 3}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: erase range of elements :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650331
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to erase elements from begin to begin+2 (2 elements) in a deque
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3, 4, 5};
|
||||||
|
d.erase(d.begin(), d.begin() + 2); // {3, 4, 5}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: swap two deques :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650326
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to swap the contents of two deques
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d1 = {1, 2, 3};
|
||||||
|
std::deque<int> d2 = {4, 5, 6};
|
||||||
|
d1.swap(d2); // d1 = {4,5,6}, d2 = {1,2,3}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: emplace at specific position :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650322
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to construct a pair in-place at position begin of a deque
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<std::pair<int,int>> d;
|
||||||
|
d.emplace(d.begin(), 1, 2); // constructs pair{1,2} at begin
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: assign new contents to deque :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650318
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to replace all contents of a deque with 5 copies of 99
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d = {1, 2, 3};
|
||||||
|
d.assign(5, 99); // {99, 99, 99, 99, 99}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: assign from range :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650314
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to replace deque contents with all elements from a vector
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> d;
|
||||||
|
std::vector<int> v = {10, 20, 30};
|
||||||
|
d.assign(v.begin(), v.end()); // {10, 20, 30}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: use deque as FIFO queue :cpp:deque:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777825650305
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write how to use deque as a FIFO queue (enqueue 1, 2, 3 then dequeue all)
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::deque<int> q;
|
||||||
|
q.push_back(1); // enqueue
|
||||||
|
q.push_back(2);
|
||||||
|
q.push_back(3);
|
||||||
|
|
||||||
|
while (!q.empty()) {
|
||||||
|
std::cout << q.front() << " ";
|
||||||
|
q.pop_front(); // dequeue
|
||||||
|
}
|
||||||
|
// Output: 1 2 3
|
||||||
|
#+end_src
|
||||||
@@ -44,6 +44,9 @@ What are the four required operations for a C++ iterator?
|
|||||||
** Front
|
** Front
|
||||||
List the five iterator categories in C++ (from simplest to most advanced)
|
List the five iterator categories in C++ (from simplest to most advanced)
|
||||||
** Back
|
** Back
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_ID: 1777826854918
|
||||||
|
:END:
|
||||||
1. Input Iterator — read values, advance once
|
1. Input Iterator — read values, advance once
|
||||||
2. Output Iterator — write values, advance once
|
2. Output Iterator — write values, advance once
|
||||||
3. Forward Iterator — read/write, multiple passes
|
3. Forward Iterator — read/write, multiple passes
|
||||||
|
|||||||
+219
@@ -0,0 +1,219 @@
|
|||||||
|
* Task: Create a std::map with initial values :cpp:map:retrieval:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734300
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write C++ code to create a ~std::map<std::string, int>~ initialized with ~{{"apple", 1}, {"banana", 2}}~
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::map<std::string, int> m = {{"apple", 1}, {"banana", 2}};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: Access a map element safely with at() :cpp:map:retrieval:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734296
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write code to safely access ~m.at("apple")~ from a ~std::map<std::string, int>~
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::map<std::string, int> m = {{"apple", 1}};
|
||||||
|
int val = m.at("apple"); // returns 1, throws if not found
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: Insert into map with insert() :cpp:map:retrieval:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734292
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write code to insert ~{"cherry", 3}~ into a ~std::map<std::string, int>~ using ~insert()~
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
auto [it, success] = m.insert({"cherry", 3});
|
||||||
|
// Returns pair<iterator, bool> — success is true if inserted
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: Insert or assign with insert_or_assign :cpp:map:retrieval:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734288
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write code to insert ~{"apple", 99}~ or update it if it already exists
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
auto [it, inserted] = m.insert_or_assign("apple", 99);
|
||||||
|
// If "apple" exists, updates value to 99
|
||||||
|
// inserted is false if key existed, true if newly inserted
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: Construct element in-place with emplace :cpp:map:retrieval:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734284
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write code to construct a ~std::map<std::string, std::vector<int>>~ element in-place without copying
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
std::map<std::string, std::vector<int>> m;
|
||||||
|
m.emplace(std::piecewise_construct,
|
||||||
|
std::forward_as_tuple("nums"),
|
||||||
|
std::forward_as_tuple(3, 1)); // vector with {1,1,1}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: Insert only if key missing with try_emplace :cpp:map:retrieval:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734280
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write code to only insert "banana" if it's NOT already in the map
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
m.try_emplace("banana", 99);
|
||||||
|
// Does nothing if "banana" exists, inserts if missing
|
||||||
|
// Unlike insert_or_assign, never overwrites existing value
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: Iterate over all key-value pairs :cpp:map:retrieval:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734276
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write code to iterate over a ~std::map<std::string, int>~ and print all key-value pairs
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
for (const auto& [key, val] : m) {
|
||||||
|
std::cout << key << ": " << val << "\n";
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: Check if key exists with contains (C++20) :cpp:map:retrieval:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734272
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write code to check if "apple" exists in a ~std::map<std::string, int>~ using C++20
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
if (m.contains("apple")) {
|
||||||
|
// key exists
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: Find element and check existence :cpp:map:retrieval:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734268
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write code to find "apple" in a map and only process if found
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
auto it = m.find("apple");
|
||||||
|
if (it != m.end()) {
|
||||||
|
// it->first = key, it->second = value
|
||||||
|
int val = it->second;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: Erase element by key :cpp:map:retrieval:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734264
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write code to remove the element with key "apple" from a ~std::map~
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
size_t erased = m.erase("apple");
|
||||||
|
// Returns number of elements erased (0 or 1)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Task: Range query with lower_bound and upper_bound :cpp:map:retrieval:production:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734260
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write code to find all elements with keys between "apple" and "cherry" (inclusive)
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
auto [start, end] = m.equal_range("apple");
|
||||||
|
// lower_bound = first >= "apple"
|
||||||
|
// upper_bound = first > "apple"
|
||||||
|
for (auto it = start; it != end; ++it) {
|
||||||
|
// process it->first, it->second
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* std::map vs std::unordered_map :cpp:map:retrieval:comparison:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734256
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What are the key differences between ~std::map~ and ~std::unordered_map~?
|
||||||
|
** Back
|
||||||
|
- ~std::map~: sorted by key, O(log n) operations, uses red-black tree
|
||||||
|
- ~std::unordered_map~: unsorted, O(1) avg operations, uses hash table
|
||||||
|
- Use ~std::map~ when you need sorted iteration or range queries
|
||||||
|
- Use ~std::unordered_map~ when you need fastest lookups and order doesn't matter
|
||||||
|
|
||||||
|
* What is value_type for std::map? :cpp:map:retrieval:recognition:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734252
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What is the ~value_type~ of ~std::map<Key, T>~?
|
||||||
|
** Back
|
||||||
|
~std::pair<const Key, T>~
|
||||||
|
|
||||||
|
* insert() return type :cpp:map:retrieval:recognition:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734247
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What does ~insert()~ return on a ~std::map~?
|
||||||
|
** Back
|
||||||
|
~std::pair<iterator, bool>~
|
||||||
|
- ~iterator~ points to the inserted (or existing) element
|
||||||
|
- ~bool~ is ~true~ if insertion happened, ~false~ if key already existed
|
||||||
|
|
||||||
|
* Why avoid operator[] for lookup? :cpp:map:retrieval:recognition:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734242
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Why is it risky to use ~map["missing"]~ to check if a key exists?
|
||||||
|
** Back
|
||||||
|
~operator[]~ inserts a default-constructed value if the key doesn't exist, modifying the map as a side effect. Use ~find()~ or ~contains()~ (C++20) for read-only lookup.
|
||||||
|
|
||||||
|
* What does extract() do? (C++17) :cpp:map:retrieval:recognition:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734238
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What does ~m.extract(key)~ do on a ~std::map~?
|
||||||
|
** Back
|
||||||
|
Removes the element with that key and returns a ~node_type~ (a node handle). The node can be inserted into another container without copying. O(log n) but no allocator overhead.
|
||||||
|
|
||||||
|
* What does merge() do? (C++17) :cpp:map:retrieval:recognition:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 1777821734232
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What does ~m1.merge(m2)~ do?
|
||||||
|
** Back
|
||||||
|
Transfers elements from ~m2~ to ~m1~. For each element transferred, if a key already exists in ~m1~, that element stays in ~m2~. No element copies are made.
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#+title: C++ Tricks
|
||||||
|
|
||||||
|
* Rotate String Check :string:trick:search:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:ANKI_NOTE_ID: 20260504001
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
How to check if string ~s~ can be rotated to match string ~goal~ in O(n)?
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
bool rotateString(string s, string goal) {
|
||||||
|
return s.size() == goal.size() && (s + s).find(goal) != string::npos;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
If ~goal~ is a substring of ~s + s~, then ~s~ can be rotated to match ~goal~.
|
||||||
@@ -0,0 +1,402 @@
|
|||||||
|
* Ufds: Union-Find Disjoint Set :cpp:datastructure:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write a minimal Ufds class with vector parent, constructor initializing parents to self
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
#include <vector>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
class Ufds {
|
||||||
|
private:
|
||||||
|
std::vector<int> parent;
|
||||||
|
public:
|
||||||
|
Ufds(int n) : parent(n) {
|
||||||
|
std::iota(parent.begin(), parent.end(), 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Ufds find() with path compression :cpp:datastructure:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Write the ~find()~ method for Ufds with path compression
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int find(int x) {
|
||||||
|
if (parent[x] != x) {
|
||||||
|
parent[x] = find(parent[x]);
|
||||||
|
}
|
||||||
|
return parent[x];
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Concise Ufds find() :cpp:datastructure:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Is this correct? What does it do?
|
||||||
|
#+begin_src c++
|
||||||
|
int find(int x) {
|
||||||
|
if (parent[x] == x) return x;
|
||||||
|
return parent[x] = find(parent[x]);
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
** Back
|
||||||
|
Yes, correct and equivalent to the longer version.
|
||||||
|
|
||||||
|
- Base case: if ~x~ is its own parent, return ~x~
|
||||||
|
- Recursive case: find root of parent, then assign and return
|
||||||
|
|
||||||
|
The assignment ~parent[x] = find(parent[x])~ returns the result while compressing the path.
|
||||||
|
|
||||||
|
* Ufds constructor: initializer list vs body :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What is the difference between these two Ufds constructors?
|
||||||
|
#+begin_src c++
|
||||||
|
// Initializer list
|
||||||
|
Ufds(int n) : parent(n) {
|
||||||
|
std::iota(parent.begin(), parent.end(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Body style
|
||||||
|
Ufds(int n) {
|
||||||
|
parent.resize(n);
|
||||||
|
std::iota(parent.begin(), parent.end(), 0);
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
** Back
|
||||||
|
Initializer list: direct constructs ~parent~ with size ~n~ (one allocation)
|
||||||
|
|
||||||
|
Body style: default constructs ~parent~, then resize (potential double allocation)
|
||||||
|
|
||||||
|
Both produce same result, initializer list is more efficient.
|
||||||
|
|
||||||
|
* What does std::vector::resize do? :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What does ~resize(n)~ do on a ~std::vector<int>~?
|
||||||
|
** Back
|
||||||
|
Resizes the vector to have ~n~ elements:
|
||||||
|
|
||||||
|
- If ~n~ > current size: adds elements (value-initialized, usually 0)
|
||||||
|
- If ~n~ < current size: truncates the vector
|
||||||
|
- Reallocates if capacity < n
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
std::vector<int> v;
|
||||||
|
v.resize(5); // v = {0, 0, 0, 0, 0}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Ufds destructor: when to omit :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Should Ufds have a destructor? ~Ufds() {}~ vs ~Ufds() = default~
|
||||||
|
** Back
|
||||||
|
Omit entirely if only using ~std::vector~ (auto-cleanup)
|
||||||
|
|
||||||
|
If you must write one, prefer ~= default~ to explicitly show intent
|
||||||
|
|
||||||
|
Empty ~{}~ works but ~= default~ is clearer intent for future maintenance
|
||||||
|
|
||||||
|
* Correct Ufds constructor: is this correct? :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Is this correct?
|
||||||
|
#+begin_src c++
|
||||||
|
Ufds(int n) {
|
||||||
|
p.resize(n);
|
||||||
|
std::iota(p.begin(), p.end(), 0);
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
** Back
|
||||||
|
Yes, correct. This is the body-style initialization.
|
||||||
|
|
||||||
|
One potential issue: ~p~ is default-constructed first, then ~resize~ may reallocate.
|
||||||
|
|
||||||
|
For efficiency, prefer initializer list: ~Ufds(int n) : p(n)~
|
||||||
|
|
||||||
|
* Incorrect Ufds constructor: correct or wrong? :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Is this correct?
|
||||||
|
#+begin_src c++
|
||||||
|
std::vector<int> p;
|
||||||
|
Ufds(int n) {
|
||||||
|
p = new std::vector<int>(n);
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
** Back
|
||||||
|
Wrong.
|
||||||
|
|
||||||
|
~new std::vector<int>(n)~ returns a ~vector<int>*~ (pointer), but ~p~ is a ~vector<int>~ (not a pointer).
|
||||||
|
|
||||||
|
Can't assign a pointer to a vector.
|
||||||
|
|
||||||
|
* What does new return? :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What does ~new Type~ return? And ~new Type[n]~?
|
||||||
|
** Back
|
||||||
|
~new Type~ returns a pointer to that type: ~Type*~
|
||||||
|
~new Type[n]~ returns a pointer to an array: ~Type*~
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
int* p1 = new int; // single int
|
||||||
|
int* p2 = new int[10]; // array of 10 ints
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* What does delete do? :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What does ~delete~ do? ~delete[]~?
|
||||||
|
** Back
|
||||||
|
~delete~ frees a single object allocated with ~new~
|
||||||
|
~delete[]~ frees an array allocated with ~new[]~
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
int* p1 = new int;
|
||||||
|
int* p2 = new int[10];
|
||||||
|
delete p1; // free single object
|
||||||
|
delete[] p2; // free array
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Mismatching ~delete~ with ~new[]~ causes undefined behavior.
|
||||||
|
|
||||||
|
* Is this correct Ufds with C-style array? :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Is this correct?
|
||||||
|
#+begin_src c++
|
||||||
|
class Ufds {
|
||||||
|
private:
|
||||||
|
int* parent;
|
||||||
|
public:
|
||||||
|
Ufds(int n) : parent(new int[n]) {}
|
||||||
|
~Ufds() { delete[] parent; }
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
** Back
|
||||||
|
Correct. This manually manages the heap-allocated array.
|
||||||
|
|
||||||
|
- ~new int[n]~ allocates array of ~n~ ints on heap
|
||||||
|
- ~delete[] parent~ in destructor frees it
|
||||||
|
|
||||||
|
This works but requires manual cleanup — error prone compared to ~std::vector~.
|
||||||
|
|
||||||
|
* Equivalent std::array version: correct or wrong? :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Is this correct?
|
||||||
|
#+begin_src c++
|
||||||
|
#include <array>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
class Ufds {
|
||||||
|
private:
|
||||||
|
std::array<int, 10> parent;
|
||||||
|
public:
|
||||||
|
Ufds() {
|
||||||
|
std::iota(parent.begin(), parent.end(), 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
** Back
|
||||||
|
Correct for compile-time fixed size.
|
||||||
|
|
||||||
|
But size ~10~ is hardcoded — not parameterized.
|
||||||
|
|
||||||
|
~std::array<T, N>~ requires ~N~ be a compile-time constant.
|
||||||
|
|
||||||
|
For runtime size, must use ~std::vector~.
|
||||||
|
|
||||||
|
* std::array vs vector vs C-style array :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Compare ~std::array<T, N>~, ~std::vector<T>~, and ~T*~ for Ufds parent array
|
||||||
|
** Back
|
||||||
|
| Type | Size | Cleanup | Use when |
|
||||||
|
|------------------+--------------+-------------------+----------------------------|
|
||||||
|
| ~std::array<T, N>~ | compile-time | automatic | size known at compile time |
|
||||||
|
| ~std::vector<T>~ | runtime | automatic | size known at runtime |
|
||||||
|
| ~T* p = new T[n]~ | runtime | manual (~delete[]~) | legacy code only |
|
||||||
|
|
||||||
|
* Vector vs Array: is vector backed by array? :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Is ~std::vector~ backed by an array? How does it support variable length?
|
||||||
|
** Back
|
||||||
|
Yes, ~std::vector~ allocates a contiguous memory block (like a heap array).
|
||||||
|
|
||||||
|
Typical implementation: three pointers
|
||||||
|
- ~start~ — pointer to data
|
||||||
|
- ~finish~ — pointer to last element
|
||||||
|
- ~end_of_storage~ — pointer to end of allocated capacity
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
vector<int> v(5);
|
||||||
|
v.push_back(1); // may trigger reallocation if capacity exceeded
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
When capacity is exceeded, vector: allocates larger block, copies elements, deallocates old block.
|
||||||
|
|
||||||
|
* Vector size vs capacity :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What is the difference between ~size()~ and ~capacity()~ in ~std::vector~?
|
||||||
|
** Back
|
||||||
|
- ~size()~ — number of actual elements stored
|
||||||
|
- ~capacity()~ — allocated storage space
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
std::vector<int> v(3); // size=3, capacity=3
|
||||||
|
v.push_back(1); // size=4, capacity may be >=4
|
||||||
|
v.push_back(1); // size=5, capacity may be >=5
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
~reserve(n)~ pre-allocates capacity without resizing.
|
||||||
|
|
||||||
|
* Comparison: which Ufds storage to use? :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
When would you choose ~std::array~, ~std::vector~, or ~T* new~ for Ufds parent array?
|
||||||
|
** Back
|
||||||
|
~std::array<T, N>~ — only if N is known at compile time
|
||||||
|
|
||||||
|
~std::vector<T>~ — if size is determined at runtime (typical Ufds case)
|
||||||
|
|
||||||
|
~T* new T[n]~ — legacy code only; ~vector~ is safer and equivalent performance
|
||||||
|
|
||||||
|
For Ufds: ~std::vector~ is the idiomatic choice because size is runtime-determined.
|
||||||
|
|
||||||
|
* C-style array key properties :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What are key properties of C-style arrays (raw arrays)?
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int arr[5]; // fixed size, stack-allocated
|
||||||
|
int* p = new int[n]; // dynamic size, heap-allocated
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
- Decay to pointer on function call (lose size info)
|
||||||
|
- No bounds checking
|
||||||
|
- ~sizeof(arr)~ gives bytes, not element count
|
||||||
|
- Must manage lifetime manually for heap arrays
|
||||||
|
|
||||||
|
C-style arrays in C++ are generally avoided in favor of ~std::array~/~std::vector~.
|
||||||
|
|
||||||
|
* std::iota for Ufds initialization :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
How to use ~std::iota~ to initialize Ufds parent array to ~[0, 1, 2, ..., n-1]~
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
std::vector<int> parent(n);
|
||||||
|
std::iota(parent.begin(), parent.end(), 0);
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
~iota~ fills the range with consecutive values starting from given start value
|
||||||
|
|
||||||
|
* Path compression in find() :cpp:datastructure:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What does "path compression" mean in ~find()~?
|
||||||
|
** Back
|
||||||
|
After finding the root, point each visited node directly to the root:
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
parent[x] = find(parent[x]); // compresses path
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
This flattens the tree structure, making future ~find()~ calls O(α(n)) ≈ O(1)
|
||||||
|
|
||||||
|
* Original Ufds mistakes: is this correct? :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Is this correct?
|
||||||
|
#+begin_src c++
|
||||||
|
class Udfs {
|
||||||
|
int parent[];
|
||||||
|
vector<int> p;
|
||||||
|
public:
|
||||||
|
Ufds(int n) {
|
||||||
|
p = new vector<int>;
|
||||||
|
}
|
||||||
|
~Ufds() {
|
||||||
|
p ? free p;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
** Back
|
||||||
|
Wrong. Multiple errors:
|
||||||
|
|
||||||
|
1. ~int parent[]~ — illegal incomplete array type
|
||||||
|
|
||||||
|
2. ~Ufds(int n)~ constructor but class is ~Udfs~ (typo)
|
||||||
|
|
||||||
|
3. ~p = new vector<int>~ — can't assign pointer to vector
|
||||||
|
|
||||||
|
4. ~free p~ — can't free a vector, and ~p~ is not a pointer
|
||||||
|
|
||||||
|
5. ~Ufds~ destructor but class is ~Udfs~ (typo)
|
||||||
|
|
||||||
|
* Heap allocation: what and why? :cpp:cpp:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What does "heap allocated" mean? Why use it?
|
||||||
|
** Back
|
||||||
|
Heap allocation with ~new~ lives until ~delete~ is called or program ends.
|
||||||
|
|
||||||
|
Stack allocation (local variables) is自动 freed when out of scope.
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
int arr[10]; // stack — freed when function returns
|
||||||
|
int* p = new int[10]; // heap — lives until delete[]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Heap needed when: size unknown at compile time, or object must outlive scope.
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#+title: Bit Tree
|
||||||
|
* binary indexd tree
|
||||||
|
#+begin_src python :results output
|
||||||
|
class BinaryIndexedTree:
|
||||||
|
def __init__(self, n: int):
|
||||||
|
self.tree = [0] * (n + 1)
|
||||||
|
def update(self, i: int, delta: int) -> None:
|
||||||
|
"""Add delta to element at index i (0-based)."""
|
||||||
|
idx = i + 1
|
||||||
|
while idx < len(self.tree):
|
||||||
|
self.tree[idx] += delta
|
||||||
|
idx += idx & (-idx)
|
||||||
|
def query(self, i: int) -> int:
|
||||||
|
"""Return prefix sum from 0 to i (0-based)."""
|
||||||
|
idx = i + 1
|
||||||
|
s = 0
|
||||||
|
while idx > 0:
|
||||||
|
s += self.tree[idx]
|
||||||
|
idx -= idx & (-idx)
|
||||||
|
return s
|
||||||
|
def range_query(self, l: int, r: int) -> int:
|
||||||
|
"""Return sum from l to r (0-based, inclusive)."""
|
||||||
|
if l == 0:
|
||||||
|
return self.query(r)
|
||||||
|
return self.query(r) - self.query(l - 1)
|
||||||
|
#+end_src
|
||||||
|
- update(i, delta) — adds delta to index i in O(log n)
|
||||||
|
- query(i) — prefix sum [0..i] in O(log n)
|
||||||
|
- range_query(l, r) — sum [l..r] in O(log n)
|
||||||
|
|
||||||
|
* min bit tree
|
||||||
|
That's a min-Fenwick (prefix minimum). Unlike sum-Fenwick, updates are point-set (not add-delta), and increasing a value is expensive — you'd need a segment tree for that.
|
||||||
|
#+begin_src python
|
||||||
|
import math
|
||||||
|
class MinFenwick:
|
||||||
|
def __init__(self, n: int, inf: int = math.inf):
|
||||||
|
self.n = n
|
||||||
|
self.inf = inf
|
||||||
|
self.tree = [inf] * (n + 1)
|
||||||
|
self.arr = [inf] * n # track actual values for rebuild
|
||||||
|
def update(self, i: int, val: int) -> None:
|
||||||
|
"""Set element at index i to val (0-based)."""
|
||||||
|
self.arr[i] = val
|
||||||
|
idx = i + 1
|
||||||
|
while idx <= self.n:
|
||||||
|
# rebuild this node from its covered range
|
||||||
|
lo = idx - (idx & (-idx)) # 0-based: lo
|
||||||
|
hi = idx - 1 # 0-based: hi
|
||||||
|
self.tree[idx] = min(self.arr[j] for j in range(lo, hi + 1))
|
||||||
|
idx += idx & (-idx)
|
||||||
|
def query(self, i: int) -> int:
|
||||||
|
"""Return min from 0 to i (0-based, inclusive)."""
|
||||||
|
idx = i + 1
|
||||||
|
res = self.inf
|
||||||
|
while idx > 0:
|
||||||
|
res = min(res, self.tree[idx])
|
||||||
|
idx -= idx & (-idx)
|
||||||
|
return res
|
||||||
|
#+end_src
|
||||||
|
- update(i, val) — set index i to val, O(log n · span) where span is the size of the covered range
|
||||||
|
- query(i) — prefix min [0..i], O(log n)
|
||||||
|
Caveat: If you need to increase a value (removing a minimum from consideration), this rebuilds the range each time — worst case O(n). For full range-min with arbitrary increases/decreases, use a segment tree instead.
|
||||||
|
|
||||||
|
* why doesn't min work with BIT?
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Why doesn't min work well with Fenwick/Bit trees? What property does addition have that min lacks?
|
||||||
|
** Back
|
||||||
|
#+begin_quote
|
||||||
|
Fenwick trees require an =invertible= operation (a group). Addition is invertible via subtraction: range_query(l,r) = prefix(r) - prefix(l-1). Min has no inverse — you can't "subtract out" the minimum of [0..l-1] from prefix(r) to get [l..r].
|
||||||
|
|
||||||
|
Additionally, min's =update= breaks on value increases. Decreasing a value works fine (like sum's decrease), but increasing a value means the old minimum might have been removed, and you'd need to scan all elements in the node's covered range to find the new minimum. This makes updates O(span) instead of O(log n).
|
||||||
|
|
||||||
|
Good Fenwick operations are associative, have an identity element, and are incrementally updateable: sum, xor, gcd. Min/max work for prefix queries only, not range queries.
|
||||||
|
#+end_quote
|
||||||
@@ -0,0 +1,763 @@
|
|||||||
|
#+title: Subarrays with Sum Equal to K
|
||||||
|
* Subarray Sum Equals K - Brute Force [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
See [[https://leetcode.com/problems/subarray-sum-equals-k/description/][LC 560]]. Find the total number of continuous subarrays whose sum equals k. Solve using the brute force approach.
|
||||||
|
Example: nums = [1,2,3], k = 3 → Output: 2 ([1,2] and [3])
|
||||||
|
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int subarraySum(vector<int>& nums, int k) {
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < nums.size(); i++) {
|
||||||
|
int sum = 0;
|
||||||
|
for (int j = i; j < nums.size(); j++) {
|
||||||
|
sum += nums[j];
|
||||||
|
if (sum == k) count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n^2), Space: O(1)
|
||||||
|
|
||||||
|
* Subarray Sum Equals K - Prefix Sum + Hash Map [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
See [[https://leetcode.com/problems/subarray-sum-equals-k/description/][LC 560]]. Find the total number of continuous subarrays whose sum equals k. Solve optimally using prefix sum with a hash map.
|
||||||
|
Example: nums = [1,2,3], k = 3 → Output: 2
|
||||||
|
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int subarraySum(vector<int>& nums, int k) {
|
||||||
|
unordered_map<int,int> prefixCount;
|
||||||
|
prefixCount[0] = 1; // base case: sum of 0 appears once
|
||||||
|
int sum = 0, count = 0;
|
||||||
|
for (int num : nums) {
|
||||||
|
sum += num;
|
||||||
|
// If (sum - k) exists, those prefixes form valid subarrays
|
||||||
|
count += prefixCount[sum - k];
|
||||||
|
prefixCount[sum]++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n), Space: O(n)
|
||||||
|
|
||||||
|
* Subarray Sum Equals K - Why prefixCount[0] = 1 [algorithm:interview]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
See [[https://leetcode.com/problems/subarray-sum-equals-k/description/][LC 560]]. In the optimal subarray sum solution (prefix sum + hash map), why is `prefixCount[0] = 1` initialized?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
It handles the case where a subarray starts from index 0 and its sum equals k.
|
||||||
|
|
||||||
|
When sum == k at some index, we look up prefixCount[sum - k] = prefixCount[0].
|
||||||
|
Without the initialization, this lookup would return 0, missing valid subarrays like [3] where k = 3.
|
||||||
|
|
||||||
|
The base case means: "a prefix sum of 0 exists once (before any element)" — conceptually the empty prefix.
|
||||||
|
|
||||||
|
* Subarray Sum Divisible by K [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
See [[https://leetcode.com/problems/subarray-sums-divisible-by-k/description/][LC 974]]. Find the total number of continuous subarrays whose sum is divisible by k.
|
||||||
|
Example: nums = [23,2,4,6,7], k = 6 → Output: 2 ([2,4] and [7])
|
||||||
|
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int subarraysDivByK(vector<int>& nums, int k) {
|
||||||
|
unordered_map<int,int> prefixCount;
|
||||||
|
prefixCount[0] = 1;
|
||||||
|
int sum = 0, count = 0;
|
||||||
|
for (int num : nums) {
|
||||||
|
sum += num;
|
||||||
|
// Modulo can be negative in C++, fix with ((sum % k) + k) % k
|
||||||
|
int remainder = ((sum % k) + k) % k;
|
||||||
|
count += prefixCount[remainder];
|
||||||
|
prefixCount[remainder]++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Key insight: If two prefix sums have the same remainder mod k, their subarray sum is divisible by k.
|
||||||
|
|
||||||
|
Time: O(n), Space: O(min(n, k))
|
||||||
|
|
||||||
|
* Longest Subarray Sum Equals K [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
See [[https://leetcode.com/problems/maximum-size-subarray-sum-equals-k/description/][LC 325]]. Find the maximum length of a contiguous subarray that sums to k.
|
||||||
|
Example: nums = [1,-1,5,-2,3], k = 3 → Output: 4 ([1,-1,5,-2])
|
||||||
|
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int maxSubArrayLen(vector<int>& nums, int k) {
|
||||||
|
unordered_map<int,int> firstOccurrence;
|
||||||
|
firstOccurrence[0] = 0; // sum 0 at index 0 (1-based)
|
||||||
|
int sum = 0, maxLen = 0;
|
||||||
|
for (int i = 0; i < nums.size(); i++) {
|
||||||
|
sum += nums[i];
|
||||||
|
// Check if subarray ending here sums to k
|
||||||
|
if (firstOccurrence.count(sum - k)) {
|
||||||
|
maxLen = max(maxLen, i + 1 - firstOccurrence[sum - k]);
|
||||||
|
}
|
||||||
|
// Store first occurrence only (for longest)
|
||||||
|
if (!firstOccurrence.count(sum)) {
|
||||||
|
firstOccurrence[sum] = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxLen;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Key difference from counting: store only the *first* occurrence of each prefix sum to maximize length.
|
||||||
|
|
||||||
|
Time: O(n), Space: O(n)
|
||||||
|
|
||||||
|
* Subarray Sum Equals K - Negative Numbers? [algorithm:interview]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
See [[https://leetcode.com/problems/subarray-sum-equals-k/description/][LC 560]]. Does the prefix sum + hash map approach for "subarray sum equals k" work when the array contains negative numbers? Why?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
Yes, it works with negative numbers.
|
||||||
|
|
||||||
|
The prefix sum approach does NOT require positive-only elements. It works for any integer array because:
|
||||||
|
- prefix[j] - prefix[i] = sum[i+1..j] is always true regardless of sign
|
||||||
|
- The hash map tracks ALL prefix sums seen, positive or negative
|
||||||
|
- We only need (sum - k) to exist in the map
|
||||||
|
|
||||||
|
This makes it superior to the sliding window approach, which only works for non-negative arrays.
|
||||||
|
|
||||||
|
* Subarray Sum Equals K - Sliding Window Limitation [algorithm:interview]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
See [[https://leetcode.com/problems/subarray-sum-equals-k/description/][LC 560]]. Can you use the sliding window technique to solve "subarray sum equals k"? When does it work?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
Sliding window ONLY works when all elements are non-negative (positive or zero).
|
||||||
|
|
||||||
|
When all elements >= 0:
|
||||||
|
- Expanding the window increases the sum
|
||||||
|
- Shrinking the window decreases the sum
|
||||||
|
- This monotonicity lets us adjust the window
|
||||||
|
|
||||||
|
Sliding window fails with negative numbers because adding/removing elements doesn't monotonically change the sum.
|
||||||
|
|
||||||
|
Prefer prefix sum + hash map — it works for all cases (positive, negative, zero).
|
||||||
|
|
||||||
|
* Subarray Sum Variations — Master Table [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What's the master table of subarray sum variations and their approaches?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
| Question | Constraint | Approach | Key Data Structure | Time |
|
||||||
|
|----------|-----------|----------|-------------------|------|
|
||||||
|
| Count subarrays sum = K | Any integers | Prefix sum | unordered_map<sum, frequency> | O(n) |
|
||||||
|
| Longest subarray sum = K | Any integers | Prefix sum | unordered_map<sum, first_index> | O(n) |
|
||||||
|
| Shortest subarray sum ≥ K | Any integers | Prefix sum + monotonic deque | deque of indices | O(n) |
|
||||||
|
| Shortest subarray sum = K | Any integers | Prefix sum + ordered map | map<sum, last_index> | O(n log n) |
|
||||||
|
| Divisible by K | Any integers | Prefix sum + modulo | unordered_map<remainder, freq> | O(n) |
|
||||||
|
| Sum in range [lower, upper] | Any integers | Prefix sum + BST | multiset / Fenwick / segment tree | O(n log n) |
|
||||||
|
| Max circular subarray sum | Any integers | Kadane's + total - min_subarray | 2x Kadane | O(n) |
|
||||||
|
| Subarray sum with only positives | Positives only | Sliding window | Two pointers | O(n) |
|
||||||
|
| 2D matrix subarray sum = K | 2D grid | Fix rows, compress to 1D | Prefix sum on compressed row | O(n^3) |
|
||||||
|
| At most K distinct elements | Frequency constraint | Sliding window + freq map | Hash map of counts | O(n) |
|
||||||
|
| Subarray with exactly K ones | Binary array | Store indices of 1s | Vector of positions | O(n) |
|
||||||
|
| Two non-overlapping subarrays each = K | Any integers | Prefix sum + track both sides | 2 pass with prefix map | O(n) |
|
||||||
|
|
||||||
|
Core pattern: prefix[j] - prefix[i] = subarray(i+1..j). The variation changes what you store and query.
|
||||||
|
|
||||||
|
* Subarray Shortest Sum ≥ K — Monotonic Deque [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
See [[https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/description/][LC 862]]. Find the length of the shortest contiguous subarray with sum ≥ K. Works with negative numbers.
|
||||||
|
Example: nums = [84,-37,32,40,95], K = 167 → Output: 3
|
||||||
|
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int shortestSubarray(vector<int>& nums, int k) {
|
||||||
|
int n = nums.size();
|
||||||
|
vector<long long> prefix(n + 1, 0);
|
||||||
|
for (int i = 0; i < n; i++) prefix[i + 1] = prefix[i] + nums[i];
|
||||||
|
|
||||||
|
deque<int> dq; // stores indices, prefix[dq[j]] is increasing
|
||||||
|
int minLen = INT_MAX;
|
||||||
|
|
||||||
|
for (int i = 0; i <= n; i++) {
|
||||||
|
// If prefix[i] - prefix[dq.front()] >= K, pop front and record length
|
||||||
|
while (!dq.empty() && prefix[i] - prefix[dq.front()] >= k) {
|
||||||
|
minLen = min(minLen, i - dq.front());
|
||||||
|
dq.pop_front();
|
||||||
|
}
|
||||||
|
// Maintain monotonic increasing order of prefix values in deque
|
||||||
|
while (!dq.empty() && prefix[i] < prefix[dq.back()]) {
|
||||||
|
dq.pop_back();
|
||||||
|
}
|
||||||
|
dq.push_back(i);
|
||||||
|
}
|
||||||
|
return minLen == INT_MAX ? -1 : minLen;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n), Space: O(n)
|
||||||
|
|
||||||
|
Key insight: Maintain a deque of indices where prefix sums are increasing.
|
||||||
|
If prefix[i] - prefix[dq.front()] ≥ K, then any index after dq.front() gives a shorter valid subarray.
|
||||||
|
|
||||||
|
* Subarray Sum in Range [lower, upper] [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
See [[https://leetcode.com/problems/count-of-range-sum/description/][LC 327]]. Count the number of subarrays whose sum lies in range [lower, upper].
|
||||||
|
Example: nums = [-2,5,-1], lower = -2, upper = 2 → Output: 3 ([-2], [-1], [5,-1])
|
||||||
|
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int countRangeSum(vector<int>& nums, int lower, int upper) {
|
||||||
|
int n = nums.size();
|
||||||
|
vector<long long> prefix(n + 1, 0);
|
||||||
|
for (int i = 0; i < n; i++) prefix[i + 1] = prefix[i] + nums[i];
|
||||||
|
|
||||||
|
// Use merge sort to count valid pairs
|
||||||
|
return mergeCount(prefix, 0, n, lower, upper);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mergeCount(vector<long long>& P, int lo, int hi, int lower, int upper) {
|
||||||
|
if (lo >= hi - 1) return 0;
|
||||||
|
int mid = lo + (hi - lo) / 2;
|
||||||
|
int count = mergeCount(P, lo, mid, lower, upper)
|
||||||
|
+ mergeCount(P, mid, hi, lower, upper);
|
||||||
|
|
||||||
|
// Count valid (i, j) pairs where P[j] - P[i] in [lower, upper]
|
||||||
|
int j = mid, k = mid, t = mid;
|
||||||
|
for (int i = lo; i < mid; i++) {
|
||||||
|
while (k <= hi && P[k] - P[i] < lower) k++;
|
||||||
|
while (t <= hi && P[t] - P[i] <= upper) t++;
|
||||||
|
count += (t - k);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge step
|
||||||
|
vector<long long> temp;
|
||||||
|
int p1 = lo, p2 = mid;
|
||||||
|
while (p1 < mid && p2 < hi) {
|
||||||
|
if (P[p1] <= P[p2]) temp.push_back(P[p1++]);
|
||||||
|
else temp.push_back(P[p2++]);
|
||||||
|
}
|
||||||
|
while (p1 < mid) temp.push_back(P[p1++]);
|
||||||
|
while (p2 < hi) temp.push_back(P[p2++]);
|
||||||
|
for (int i = 0; i < (int)temp.size(); i++) P[lo + i] = temp[i];
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n log n), Space: O(n)
|
||||||
|
|
||||||
|
Why not hash map? Hash map can't count how many prefix sums fall in a range.
|
||||||
|
Merge sort counts (i, j) pairs where P[j] - P[i] ∈ [lower, upper] during the merge step.
|
||||||
|
|
||||||
|
* Max Circular Subarray Sum [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
See [[https://leetcode.com/problems/maximum-sum-circular-subarray/description/][LC 918]]. Find the maximum sum of a non-empty subarray in a circular array.
|
||||||
|
Example: nums = [1,-2,3,-2] → Output: 3
|
||||||
|
Example: nums = [5,-3,5] → Output: 10 (wraps around: [5, 5])
|
||||||
|
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int maxSubarraySumCircular(vector<int>& nums) {
|
||||||
|
int total = 0, maxSum = nums[0], curMax = 0;
|
||||||
|
int minSum = nums[0], curMin = 0;
|
||||||
|
|
||||||
|
for (int num : nums) {
|
||||||
|
curMax = max(curMax + num, num);
|
||||||
|
maxSum = max(maxSum, curMax);
|
||||||
|
curMin = min(curMin + num, num);
|
||||||
|
minSum = min(minSum, curMin);
|
||||||
|
total += num;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all numbers are negative, maxSum is the answer (total - minSum = 0)
|
||||||
|
return maxSum < 0 ? maxSum : max(maxSum, total - minSum);
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n), Space: O(1)
|
||||||
|
|
||||||
|
Two cases:
|
||||||
|
1. Maximum subarray does NOT wrap — standard Kadane's (maxSum)
|
||||||
|
2. Maximum subarray DOES wrap — total - minSubarray (remove the minimum subarray from the middle)
|
||||||
|
|
||||||
|
Edge case: all negative → total - minSum = 0, which is wrong. Return maxSum instead.
|
||||||
|
|
||||||
|
* 2D Matrix Subarray Sum = K [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
See [[https://leetcode.com/problems/number-of-submatrices-that-sum-to-target/description/][Submatrices Sum to Target]]. Given a 2D matrix, find the number of submatrices whose sum equals K.
|
||||||
|
Example: matrix = [[0,1,0],[1,1,1],[0,1,0]], K = 0 → Output: 4
|
||||||
|
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int numSubmatrixSumTarget(vector<vector<int>>& matrix, int target) {
|
||||||
|
int m = matrix.size(), n = matrix[0].size();
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
// Fix top and bottom rows, compress to 1D array
|
||||||
|
for (int r1 = 0; r1 < m; r1++) {
|
||||||
|
vector<int> colSum(n, 0);
|
||||||
|
for (int r2 = r1; r2 < m; r2++) {
|
||||||
|
// Add row r2 to the compressed column sums
|
||||||
|
for (int c = 0; c < n; c++) {
|
||||||
|
colSum[c] += matrix[r2][c];
|
||||||
|
}
|
||||||
|
// Now solve 1D subarray sum = target
|
||||||
|
unordered_map<int,int> prefixCount;
|
||||||
|
prefixCount[0] = 1;
|
||||||
|
int sum = 0;
|
||||||
|
for (int val : colSum) {
|
||||||
|
sum += val;
|
||||||
|
count += prefixCount[sum - target];
|
||||||
|
prefixCount[sum]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(m^2 * n), Space: O(n)
|
||||||
|
|
||||||
|
Key idea: Fix two rows (r1, r2), compress columns between them into a 1D array.
|
||||||
|
Then the problem reduces to 1D subarray sum = K.
|
||||||
|
|
||||||
|
* Exactly K Distinct Elements with Sum = K [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the length of the longest subarray with at most K distinct elements and sum = K.
|
||||||
|
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int longestSubarray(vector<int>& nums, int k) {
|
||||||
|
unordered_map<int,int> freq;
|
||||||
|
int sum = 0, distinct = 0, maxLen = 0;
|
||||||
|
int left = 0;
|
||||||
|
|
||||||
|
for (int right = 0; right < nums.size(); right++) {
|
||||||
|
if (freq[nums[right]] == 0) distinct++;
|
||||||
|
freq[nums[right]]++;
|
||||||
|
sum += nums[right];
|
||||||
|
|
||||||
|
// Shrink while distinct > K or sum > k
|
||||||
|
while (distinct > k || sum > k) {
|
||||||
|
freq[nums[left]]--;
|
||||||
|
if (freq[nums[left]] == 0) distinct--;
|
||||||
|
sum -= nums[left];
|
||||||
|
left++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sum == k) maxLen = max(maxLen, right - left + 1);
|
||||||
|
}
|
||||||
|
return maxLen;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n), Space: O(min(n, K))
|
||||||
|
|
||||||
|
This combines sliding window (distinct elements constraint) with sum check.
|
||||||
|
The two constraints (distinct count + sum) make it trickier than simple sliding window.
|
||||||
|
|
||||||
|
* Binary Array — Exactly K Ones [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
See [[https://leetcode.com/problems/max-consecutive-ones-iii/description/][LC 1004]]. Given a binary array nums and an integer k, return the maximum number of consecutive 1's in the array if you can flip at most k 0's.
|
||||||
|
Example: nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2 → Output: 6
|
||||||
|
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int longestOnes(vector<int>& nums, int k) {
|
||||||
|
int left = 0, maxLen = 0;
|
||||||
|
for (int right = 0; right < nums.size(); right++) {
|
||||||
|
if (nums[right] == 0) k--;
|
||||||
|
while (k < 0) {
|
||||||
|
if (nums[left] == 0) k++;
|
||||||
|
left++;
|
||||||
|
}
|
||||||
|
maxLen = max(maxLen, right - left + 1);
|
||||||
|
}
|
||||||
|
return maxLen;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n), Space: O(1)
|
||||||
|
|
||||||
|
Sliding window: expand right, count zeros. When zeros exceed k, shrink from left.
|
||||||
|
|
||||||
|
* Two Non-Overlapping Subarrays Each Sum = K [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the maximum sum of two non-overlapping subarrays with lengths L and M.
|
||||||
|
Example: nums = [0,6,5,2,2,5,1,9,4], L = 1, M = 2 → Output: 20 ([9] and [6,5])
|
||||||
|
|
||||||
|
** Back
|
||||||
|
#+begin_src c++
|
||||||
|
int maxSumTwoNoOverlap(vector<int>& nums, int L, int M) {
|
||||||
|
int n = nums.size();
|
||||||
|
// Prefix sums for O(1) subarray sum queries
|
||||||
|
vector<int> prefix(n + 1, 0);
|
||||||
|
for (int i = 0; i < n; i++) prefix[i + 1] = prefix[i] + nums[i];
|
||||||
|
|
||||||
|
auto sum = [&](int i, int j) { return prefix[j + 1] - prefix[i]; };
|
||||||
|
|
||||||
|
int maxL = 0, maxM = 0, result = 0;
|
||||||
|
|
||||||
|
// Case 1: L comes before M
|
||||||
|
for (int i = L + M; i <= n; i++) {
|
||||||
|
maxL = max(maxL, sum(i - L - M, i - M - 1));
|
||||||
|
maxM = max(maxM, sum(i - M, i - 1));
|
||||||
|
result = max(result, maxL + maxM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2: M comes before L
|
||||||
|
maxL = 0; maxM = 0; result = 0;
|
||||||
|
for (int i = L + M; i <= n; i++) {
|
||||||
|
maxM = max(maxM, sum(i - L - M, i - L - 1));
|
||||||
|
maxL = max(maxL, sum(i - L, i - 1));
|
||||||
|
result = max(result, maxL + maxM);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n), Space: O(n)
|
||||||
|
|
||||||
|
Two cases: L before M, or M before L.
|
||||||
|
Track the running maximum of the first subarray while computing the second.
|
||||||
|
|
||||||
|
* Subarray Sum — All Relationships Diagram [algorithm:interview]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What's the decision tree for choosing the right subarray sum approach?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
1. **Are there negative numbers?**
|
||||||
|
→ YES: Prefix sum approach (hash map, BST, or merge sort)
|
||||||
|
→ NO: Sliding window is possible
|
||||||
|
|
||||||
|
2. **What are you counting?**
|
||||||
|
→ Count all: hash_map<sum, frequency>
|
||||||
|
→ Longest: hash_map<sum, first_index>
|
||||||
|
→ Shortest: hash_map<sum, last_index> or monotonic deque
|
||||||
|
|
||||||
|
3. **Is the target a range [lower, upper]?**
|
||||||
|
→ YES: Merge sort (count pairs in range) or Fenwick tree / BST
|
||||||
|
|
||||||
|
4. **Is it divisible by K?**
|
||||||
|
→ YES: hash_map<remainder, frequency> with modulo
|
||||||
|
|
||||||
|
5. **Is the array circular?**
|
||||||
|
→ YES: Kadane's twice — max(max_subarray, total - min_subarray)
|
||||||
|
|
||||||
|
6. **Is it 2D?**
|
||||||
|
→ YES: Fix 2 rows, compress to 1D, then prefix sum
|
||||||
|
|
||||||
|
7. **Are elements only 0/1?**
|
||||||
|
→ YES: Store indices of 1s, or sliding window counting zeros
|
||||||
|
|
||||||
|
8. **Are there constraints on distinct elements?**
|
||||||
|
→ YES: Sliding window + frequency map
|
||||||
|
|
||||||
|
9. **Are there multiple non-overlapping subarrays?**
|
||||||
|
→ YES: 2-pass — track running max of first while computing second
|
||||||
|
|
||||||
|
The fundamental identity: subarray(i,j) = prefix[j+1] - prefix[i].
|
||||||
|
Everything else is about what you do with the prefix array.
|
||||||
|
|
||||||
|
* Subarray Sum — Core Trigger Heuristic [algorithm:interview]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What is the most reliable heuristic for recognizing when to use Prefix Sums?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
When you see **"subarray"** and **"sum"** in the same problem description, **Prefix Sums** should be your immediate first thought.
|
||||||
|
|
||||||
|
The core formula:
|
||||||
|
Sum(i..j) = PrefixSum[j] - PrefixSum[i-1]
|
||||||
|
|
||||||
|
This turns a **range query** into a **difference between two points**, eliminating the need to re-scan the array.
|
||||||
|
|
||||||
|
The mental trigger is simple: subarray + sum → prefix sums. Always.
|
||||||
|
|
||||||
|
* Subarray Sum — When to Use Sliding Window vs Prefix Sum [algorithm:interview]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
When should you use Sliding Window vs Prefix Sum + Hash Map for subarray sum problems?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
| Condition | Use | Why |
|
||||||
|
|-----------|-----|-----|
|
||||||
|
| All numbers ≥ 0, need target sum or max length | **Sliding Window** | Monotonic: expanding always increases sum, shrinking always decreases. O(1) space vs O(n). |
|
||||||
|
| Numbers can be negative, need exact target sum | **Prefix Sum + Hash Map** | Monotonicity broken. Adding an element could make sum smaller. Must remember past states. |
|
||||||
|
| Frequent updates between queries | **Fenwick Tree / Segment Tree** | Prefix sum array takes O(n) to update. Trees give O(log n) update + query. |
|
||||||
|
|
||||||
|
Rule of thumb: check for negative numbers first. If none exist, sliding window wins.
|
||||||
|
|
||||||
|
* Subarray Product — Prefix Product Pattern [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
How does the prefix sum pattern translate to subarray **product** problems?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
The prefix sum pattern translates directly into a **Prefix Product**:
|
||||||
|
|
||||||
|
Product(i..j) = PrefixProduct[j] / PrefixProduct[i-1]
|
||||||
|
|
||||||
|
Instead of subtracting, you divide.
|
||||||
|
|
||||||
|
Edge case: zeros break division. Handle by:
|
||||||
|
1. Segmentation — split the array at zeros, solve each segment independently
|
||||||
|
2. Track position of last seen zero to reset boundaries
|
||||||
|
|
||||||
|
Example: count subarrays with product < K (all positive):
|
||||||
|
#+begin_src c++
|
||||||
|
int numSubarrayProductLessThanK(vector<int>& nums, int k) {
|
||||||
|
if (k == 0) return 0;
|
||||||
|
int count = 0, product = 1, left = 0;
|
||||||
|
for (int right = 0; right < nums.size(); right++) {
|
||||||
|
product *= nums[right];
|
||||||
|
while (left <= right && product >= k) product /= nums[left++];
|
||||||
|
count += right - left + 1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Subarray with Equal 0s and 1s — Value Mapping [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the maximum length of a contiguous subarray with equal number of 0s and 1s.
|
||||||
|
Example: nums = [1,0,1] → Output: 2 ([1,0] or [0,1])
|
||||||
|
|
||||||
|
** Back
|
||||||
|
Treat 0 as -1 and 1 as +1. The problem becomes: **"Find the longest subarray whose sum equals 0."**
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
int findMaxLength(vector<int>& nums) {
|
||||||
|
unordered_map<int,int> firstOccurrence;
|
||||||
|
firstOccurrence[0] = 0; // sum 0 at index 0 (1-based)
|
||||||
|
int sum = 0, maxLen = 0;
|
||||||
|
for (int i = 0; i < nums.size(); i++) {
|
||||||
|
sum += (nums[i] == 1) ? 1 : -1;
|
||||||
|
if (firstOccurrence.count(sum)) {
|
||||||
|
maxLen = max(maxLen, i + 1 - firstOccurrence[sum]);
|
||||||
|
} else {
|
||||||
|
firstOccurrence[sum] = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxLen;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n), Space: O(n)
|
||||||
|
|
||||||
|
This is the **"prefix state"** generalization: map values to +1/-1, then it's just prefix sum = 0.
|
||||||
|
|
||||||
|
* Subarray with Equal Odd and Even Numbers [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the longest subarray with equal number of odd and even numbers.
|
||||||
|
|
||||||
|
** Back
|
||||||
|
Map every even number to +1 and every odd number to -1 (or vice versa). The problem becomes:
|
||||||
|
**"Find the longest subarray whose sum equals 0."**
|
||||||
|
|
||||||
|
Same approach as equal 0s and 1s: prefix sum + hash map storing first occurrence.
|
||||||
|
|
||||||
|
This is the same "prefix state" generalization applied to a different domain.
|
||||||
|
|
||||||
|
* Multi-Category Balance — (A, B, C) Equal Counts [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the longest subarray with equal number of 'A's, 'B's, and 'C's.
|
||||||
|
|
||||||
|
** Back
|
||||||
|
You can't use a single scalar (+1/-1) for three categories. Instead, track **relative differences** between counts.
|
||||||
|
|
||||||
|
Maintain running counts: c_A, c_B, c_C.
|
||||||
|
At each step, compute the tuple of differences: (c_A - c_B, c_B - c_C).
|
||||||
|
|
||||||
|
If this tuple repeats later in the array, the elements between those indices have perfectly balanced A, B, C counts.
|
||||||
|
|
||||||
|
Data structure: hash map where the key is the state tuple:
|
||||||
|
map<pair<int,int>, int> firstOccurrence;
|
||||||
|
|
||||||
|
The tuple (diff_AB, diff_BC) captures the full relative state. If two positions share the same tuple, the subarray between them has zero net change in all three relative differences → equal counts.
|
||||||
|
|
||||||
|
Time: O(n), Space: O(n)
|
||||||
|
|
||||||
|
* Subarray Product Is Positive / Negative [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the maximum length of a subarray with a positive (or negative) product.
|
||||||
|
|
||||||
|
** Back
|
||||||
|
Map: positive → +1, negative → -1, zero → resets the window.
|
||||||
|
|
||||||
|
A subarray has positive product if it contains an **even** number of negatives.
|
||||||
|
A subarray has negative product if it contains an **odd** number of negatives.
|
||||||
|
|
||||||
|
Track the parity (odd/even count) of negative numbers as you traverse:
|
||||||
|
- If parity is even at index i and was even at index j (j < i), the subarray (j+1..i) has positive product.
|
||||||
|
- If parity is odd at index i and was even at index j, the subarray (j+1..i) has negative product.
|
||||||
|
|
||||||
|
Data structure: two hash maps (or arrays) — first occurrence of even-parity index and first occurrence of odd-parity index.
|
||||||
|
|
||||||
|
Time: O(n), Space: O(n)
|
||||||
|
|
||||||
|
* Bitwise Subarray — OR / AND / XOR [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Can you use prefix sums for subarray problems with Bitwise OR, AND, or XOR?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
**XOR:** YES — XOR is invertible (XOR is its own inverse).
|
||||||
|
XOR(i..j) = PrefixXOR[j] ^ PrefixXOR[i-1]
|
||||||
|
Same hash map pattern as prefix sum.
|
||||||
|
|
||||||
|
**OR / AND:** NO — not invertible. You cannot "undo" an OR or AND operation.
|
||||||
|
|
||||||
|
For OR/AND, exploit the key property: as you expand a subarray, the OR/AND result can only change at most **32 times** (for 32-bit integers) because bits only transition 0→1 (OR) or 1→0 (AND).
|
||||||
|
|
||||||
|
Strategy: maintain a **set** of all possible OR results ending at the current index. The set never exceeds size 32.
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
int subarrayBitwiseORs(vector<int>& arr) {
|
||||||
|
unordered_set<int> result, current;
|
||||||
|
for (int x : arr) {
|
||||||
|
unordered_set<int> next;
|
||||||
|
next.insert(x);
|
||||||
|
for (int val : current) {
|
||||||
|
next.insert(val | x);
|
||||||
|
}
|
||||||
|
current = next;
|
||||||
|
for (int val : current) result.insert(val);
|
||||||
|
}
|
||||||
|
return result.size();
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n * 32), Space: O(32) per step
|
||||||
|
|
||||||
|
* Subarray Sum — Keyword-to-Algorithm Mapping [algorithm:interview]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What is the master keyword-to-algorithm mapping for subarray problems?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
| Problem Phrase | Array Property | Algorithm |
|
||||||
|
|--------------------------------------+-----------------------+----------------------------------------------|
|
||||||
|
| "Continuous subarray + Sum = K" | Only positive numbers | **Sliding Window** (O(1) space) |
|
||||||
|
| "Continuous subarray + Sum = K" | Positive & negative | **Prefix Sum + Hash Map** (O(n) space) |
|
||||||
|
| "Divisible by K" or "Multiple of X" | Any numbers | **Prefix Remainder + Hash Map** (sum % K) |
|
||||||
|
| "Equal number of X and Y" | Any numbers | **Value Mapping** (X→1, Y→-1) + Prefix Sum Map |
|
||||||
|
| "Maximum / Minimum Sum" | Any numbers | **Kadane's Algorithm** (DP) |
|
||||||
|
| "Subarray Sum + Frequent Updates" | Element mutations | **Fenwick Tree / Segment Tree** |
|
||||||
|
| "Subarray product = K" | No zeros | **Prefix Product** (division) |
|
||||||
|
| "Subarray product positive/negative" | Any numbers | **Parity tracking** of negative count |
|
||||||
|
| "Subarray XOR = K" | Any numbers | **Prefix XOR + Hash Map** |
|
||||||
|
| "Subarray OR / AND" | Any numbers | **Set of results** (bounded by 32 changes) |
|
||||||
|
|
||||||
|
* Subarray Sum — Modular Arithmetic Insight [algorithm:interview]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Why does "subarray sum divisible by K" work with prefix remainders? Prove it.
|
||||||
|
|
||||||
|
** Back
|
||||||
|
If Sum(i..j) mod K = 0, then:
|
||||||
|
(Prefix[j] - Prefix[i-1]) mod K = 0
|
||||||
|
|
||||||
|
By modular arithmetic:
|
||||||
|
Prefix[j] mod K = Prefix[i-1] mod K
|
||||||
|
|
||||||
|
**Proof:**
|
||||||
|
Prefix[j] - Prefix[i-1] = m * K (for some integer m)
|
||||||
|
Prefix[j] = Prefix[i-1] + m * K
|
||||||
|
Prefix[j] mod K = (Prefix[i-1] + m * K) mod K
|
||||||
|
Prefix[j] mod K = Prefix[i-1] mod K (since m*K mod K = 0)
|
||||||
|
|
||||||
|
So we just need to find pairs of indices with the same prefix remainder.
|
||||||
|
|
||||||
|
**Caveat:** In C++/Java, % can return negative values for negative operands. Fix:
|
||||||
|
remainder = ((prefix_sum % K) + K) % K
|
||||||
|
|
||||||
|
In Python, % always returns non-negative, so no fix needed.
|
||||||
|
|
||||||
|
* Subarray Sum — Prefix State Generalization [algorithm:concept]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What is the "prefix state" generalization, and how does it extend beyond addition?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
The core philosophy of prefix sums is: **accumulate history as you traverse linearly, and use a hash map to track state.**
|
||||||
|
|
||||||
|
This generalizes far beyond addition:
|
||||||
|
|
||||||
|
| Problem | Mapping | Reduces To |
|
||||||
|
|-------------------------+--------------------------+----------------------------|
|
||||||
|
| Equal 0s and 1s | 0→-1, 1→+1 | Subarray sum = 0 |
|
||||||
|
| Equal odd/even | even→+1, odd→-1 | Subarray sum = 0 |
|
||||||
|
| Equal vowels/consonants | vowel→+1, consonant→-1 | Subarray sum = 0 |
|
||||||
|
| Equal A/B/C counts | Track (c_A-c_B, c_B-c_C) | Prefix state tuple repeats |
|
||||||
|
| Subarray product | Prefix product | Division (handle zeros) |
|
||||||
|
| Subarray XOR | Prefix XOR | XOR is invertible |
|
||||||
|
| Subarray sum | Prefix sum | Subtraction |
|
||||||
|
|
||||||
|
The pattern:
|
||||||
|
1. Define a state that accumulates as you traverse
|
||||||
|
2. Find a way to "undo" or compare states (subtract, XOR, divide, compare tuples)
|
||||||
|
3. Use a hash map to find when the same state (or target difference) appears
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
#+title: Master Subarray Pattern Sheet
|
||||||
|
* Subarray Divisible by K — Remainder Pattern [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Why does "subarray sum divisible by K" work with prefix remainders?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
If Sum(i..j) mod K = 0, then:
|
||||||
|
(Prefix[j] - Prefix[i-1]) mod K = 0
|
||||||
|
|
||||||
|
By modular arithmetic:
|
||||||
|
Prefix[j] mod K = Prefix[i-1] mod K
|
||||||
|
|
||||||
|
So we find pairs of indices with the same prefix remainder.
|
||||||
|
|
||||||
|
Transformation: store current_sum % K in hash map.
|
||||||
|
|
||||||
|
Data structure: hash map tracking frequencies of remainders.
|
||||||
|
|
||||||
|
C++ caveat: % can return negative for negative operands. Fix:
|
||||||
|
remainder = ((prefix_sum % K) + K) % K
|
||||||
|
|
||||||
|
Python: % always non-negative, no fix needed.
|
||||||
|
|
||||||
|
* Subarray Equal 0s and 1s — Value Mapping [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the longest subarray with equal number of 0s and 1s.
|
||||||
|
Example: nums = [0,1] → Output: 2
|
||||||
|
|
||||||
|
** Back
|
||||||
|
Replace all 0s with -1. The problem becomes:
|
||||||
|
**"Find a subarray whose sum equals 0."**
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
int findMaxLength(vector<int>& nums) {
|
||||||
|
unordered_map<int,int> firstOccurrence;
|
||||||
|
firstOccurrence[0] = 0;
|
||||||
|
int sum = 0, maxLen = 0;
|
||||||
|
for (int i = 0; i < nums.size(); i++) {
|
||||||
|
sum += (nums[i] == 1) ? 1 : -1;
|
||||||
|
if (firstOccurrence.count(sum)) {
|
||||||
|
maxLen = max(maxLen, i + 1 - firstOccurrence[sum]);
|
||||||
|
} else {
|
||||||
|
firstOccurrence[sum] = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxLen;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n), Space: O(n)
|
||||||
|
|
||||||
|
Data structure: hash map tracking raw prefix sums (first occurrence).
|
||||||
|
|
||||||
|
* Subarray Equal Odd/Even Numbers — Same Pattern [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the longest subarray with equal number of odd and even numbers.
|
||||||
|
|
||||||
|
** Back
|
||||||
|
Map every even number to +1 and every odd number to -1.
|
||||||
|
The problem becomes: **"Find a subarray whose sum equals 0."**
|
||||||
|
|
||||||
|
Same approach as equal 0s and 1s: prefix sum + hash map storing first occurrence.
|
||||||
|
|
||||||
|
This is the same value mapping pattern applied to a different domain.
|
||||||
|
|
||||||
|
* Subarray Equal Vowels and Consonants [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the longest subarray with equal number of vowels and consonants.
|
||||||
|
|
||||||
|
** Back
|
||||||
|
Map: vowel → +1, consonant → -1.
|
||||||
|
The problem becomes: **"Find a subarray whose sum equals 0."**
|
||||||
|
|
||||||
|
Same prefix sum + hash map approach.
|
||||||
|
|
||||||
|
This demonstrates the general principle: any binary-counting problem can be reduced to "subarray sum = 0" via value mapping.
|
||||||
|
|
||||||
|
* Multi-Category Balance — Equal A/B/C Counts [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the longest subarray with equal number of 'A's, 'B's, and 'C's.
|
||||||
|
|
||||||
|
** Back
|
||||||
|
You can't use a single scalar (+1/-1) for three categories. Track **relative differences** between counts.
|
||||||
|
|
||||||
|
Maintain running counts: c_A, c_B, c_C.
|
||||||
|
At each step, compute the tuple of differences: (c_A - c_B, c_B - c_C).
|
||||||
|
|
||||||
|
If this tuple repeats later in the array, the elements between those indices have perfectly balanced A, B, C counts.
|
||||||
|
|
||||||
|
Data structure: hash map where the key is the state tuple:
|
||||||
|
map<pair<int,int>, int> firstOccurrence;
|
||||||
|
|
||||||
|
The tuple (diff_AB, diff_BC) captures the full relative state. If two positions share the same tuple, the subarray between them has zero net change in all three relative differences → equal counts.
|
||||||
|
|
||||||
|
Time: O(n), Space: O(n)
|
||||||
|
|
||||||
|
* Subarray Product Equals K — Prefix Product [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the number of subarrays with product equal to K.
|
||||||
|
|
||||||
|
** Back
|
||||||
|
Use a **Prefix Product** array:
|
||||||
|
Product(i..j) = PrefixProduct[j] / PrefixProduct[i-1]
|
||||||
|
|
||||||
|
Instead of subtracting, you divide.
|
||||||
|
|
||||||
|
Data structure: hash map searching for current_product / K.
|
||||||
|
|
||||||
|
Edge case: zeros reset the product to 0. Handle by:
|
||||||
|
1. Segmentation — split the array at zeros, solve each segment independently
|
||||||
|
2. Track position of last seen zero to reset boundaries
|
||||||
|
|
||||||
|
Example: subarray product less than K (all positive):
|
||||||
|
#+begin_src c++
|
||||||
|
int numSubarrayProductLessThanK(vector<int>& nums, int k) {
|
||||||
|
if (k <= 1) return 0;
|
||||||
|
int count = 0, product = 1, left = 0;
|
||||||
|
for (int right = 0; right < nums.size(); right++) {
|
||||||
|
product *= nums[right];
|
||||||
|
while (left <= right && product >= k) product /= nums[left++];
|
||||||
|
count += right - left + 1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Subarray Product Positive/Negative — Parity Tracking [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the maximum length of a subarray with a positive (or negative) product.
|
||||||
|
|
||||||
|
** Back
|
||||||
|
Map: positive → +1, negative → -1, zero → resets the window.
|
||||||
|
|
||||||
|
A subarray has positive product if it contains an **even** number of negatives.
|
||||||
|
A subarray has negative product if it contains an **odd** number of negatives.
|
||||||
|
|
||||||
|
Track the parity (odd/even count) of negative numbers as you traverse:
|
||||||
|
- If parity is even at index i and was even at index j (j < i), the subarray (j+1..i) has positive product.
|
||||||
|
- If parity is odd at index i and was even at index j, the subarray (j+1..i) has negative product.
|
||||||
|
|
||||||
|
Data structure: two hash maps — first occurrence of even-parity index and first occurrence of odd-parity index.
|
||||||
|
|
||||||
|
Time: O(n), Space: O(n)
|
||||||
|
|
||||||
|
* Subarray Bitwise XOR — Prefix XOR [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Find the number of subarrays with XOR equal to K.
|
||||||
|
|
||||||
|
** Back
|
||||||
|
XOR is invertible (XOR is its own inverse), so the prefix pattern works:
|
||||||
|
XOR(i..j) = PrefixXOR[j] ^ PrefixXOR[i-1]
|
||||||
|
|
||||||
|
Same hash map pattern as prefix sum:
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
int subarrayXOR(vector<int>& nums, int k) {
|
||||||
|
unordered_map<int,int> prefixCount;
|
||||||
|
prefixCount[0] = 1;
|
||||||
|
int sum = 0, count = 0;
|
||||||
|
for (int num : nums) {
|
||||||
|
sum ^= num;
|
||||||
|
count += prefixCount[sum ^ k];
|
||||||
|
prefixCount[sum]++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n), Space: O(n)
|
||||||
|
|
||||||
|
* Subarray Bitwise OR/AND — Non-Invertible [algorithm:array]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
Can you use prefix sums for subarray problems with Bitwise OR or AND?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
**NO.** Unlike XOR, OR/AND are **not invertible**. You cannot "undo" an OR or AND operation.
|
||||||
|
|
||||||
|
Exploit the key property: as you expand a subarray, the OR/AND result can only change at most **32 times** (for 32-bit integers) because bits only transition 0→1 (OR) or 1→0 (AND).
|
||||||
|
|
||||||
|
Strategy: maintain a **set** of all possible OR results ending at the current index. The set never exceeds size 32.
|
||||||
|
|
||||||
|
#+begin_src c++
|
||||||
|
int subarrayBitwiseORs(vector<int>& arr) {
|
||||||
|
unordered_set<int> result, current;
|
||||||
|
for (int x : arr) {
|
||||||
|
unordered_set<int> next;
|
||||||
|
next.insert(x);
|
||||||
|
for (int val : current) {
|
||||||
|
next.insert(val | x);
|
||||||
|
}
|
||||||
|
current = next;
|
||||||
|
for (int val : current) result.insert(val);
|
||||||
|
}
|
||||||
|
return result.size();
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
Time: O(n * 32), Space: O(32) per step
|
||||||
|
|
||||||
|
* Master Keyword-to-Algorithm Mapping [algorithm:interview]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What is the master keyword-to-algorithm mapping for subarray problems?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
| Problem Phrase | Array Property | Algorithm |
|
||||||
|
|---------------|---------------|-----------|
|
||||||
|
| "Continuous subarray + Sum = K" | Only positive numbers | **Sliding Window** (O(1) space) |
|
||||||
|
| "Continuous subarray + Sum = K" | Positive & negative | **Prefix Sum + Hash Map** (O(n) space) |
|
||||||
|
| "Divisible by K" or "Multiple of X" | Any numbers | **Prefix Remainder + Hash Map** (sum % K) |
|
||||||
|
| "Equal number of X and Y" | Any numbers | **Value Mapping** (X→1, Y→-1) + Prefix Sum Map |
|
||||||
|
| "Maximum / Minimum Sum" | Any numbers | **Kadane's Algorithm** (DP) |
|
||||||
|
| "Subarray Sum + Frequent Updates" | Element mutations | **Fenwick Tree / Segment Tree** |
|
||||||
|
| "Subarray product = K" | No zeros | **Prefix Product** (division) |
|
||||||
|
| "Subarray product positive/negative" | Any numbers | **Parity tracking** of negative count |
|
||||||
|
| "Subarray XOR = K" | Any numbers | **Prefix XOR + Hash Map** |
|
||||||
|
| "Subarray OR / AND" | Any numbers | **Set of results** (bounded by 32 changes) |
|
||||||
|
|
||||||
|
* Prefix State Generalization — The Unifying Concept [algorithm:concept]
|
||||||
|
:PROPERTIES:
|
||||||
|
:ANKI_NOTE_TYPE: Basic
|
||||||
|
:END:
|
||||||
|
** Front
|
||||||
|
What is the "prefix state" generalization that unifies all subarray patterns?
|
||||||
|
|
||||||
|
** Back
|
||||||
|
The core philosophy of prefix sums is: **accumulate history as you traverse linearly, and use a hash map to track state.**
|
||||||
|
|
||||||
|
| Problem | Mapping | Reduces To |
|
||||||
|
|---------|---------|-----------|
|
||||||
|
| Equal 0s and 1s | 0→-1, 1→+1 | Subarray sum = 0 |
|
||||||
|
| Equal odd/even | even→+1, odd→-1 | Subarray sum = 0 |
|
||||||
|
| Equal vowels/consonants | vowel→+1, consonant→-1 | Subarray sum = 0 |
|
||||||
|
| Equal A/B/C counts | Track (c_A-c_B, c_B-c_C) | Prefix state tuple repeats |
|
||||||
|
| Subarray product | Prefix product | Division (handle zeros) |
|
||||||
|
| Subarray XOR | Prefix XOR | XOR is invertible |
|
||||||
|
| Subarray sum | Prefix sum | Subtraction |
|
||||||
|
|
||||||
|
The pattern:
|
||||||
|
1. Define a state that accumulates as you traverse
|
||||||
|
2. Find a way to "undo" or compare states (subtract, XOR, divide, compare tuples)
|
||||||
|
3. Use a hash map to find when the same state (or target difference) appears
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#+title: Subarray Sum — Pattern Recognition Guide
|
||||||
|
#+AUTHOR: Noramyll
|
||||||
|
|
||||||
|
* Core Trigger: Subarray + Sum
|
||||||
|
|
||||||
|
When you see **"subarray"** and **"sum"** in the same problem description, **Prefix Sums** should almost always be your immediate first thought.
|
||||||
|
|
||||||
|
The fundamental formula:
|
||||||
|
|
||||||
|
Sum(i..j) = PrefixSum[j] - PrefixSum[i-1]
|
||||||
|
|
||||||
|
This algebraic rewrite turns a **range query** into a **difference between two points**. It completely eliminates the need to re-scan the array.
|
||||||
|
|
||||||
|
The mental trigger is simple: subarray + sum → prefix sums. Always.
|
||||||
|
|
||||||
|
**Variations of this pattern:**
|
||||||
|
|
||||||
|
- **"Count of subarrays where sum equals K"**: Use the hash map approach, looking for `current_sum - K`.
|
||||||
|
- **"Longest/Shortest subarray where sum equals K"**: Instead of storing the *frequency* of the prefix sum in your map, store its **first seen index** (`map[prefix_sum] = index`). This lets you track length via `current_index - map[current_sum - K]`.
|
||||||
|
- **"Subarray sum divisible by K"**: Store `prefix_sum % K` in your hash map instead of the raw sum.
|
||||||
|
|
||||||
|
* The Multiplicative Variant: Subarray + Product
|
||||||
|
|
||||||
|
If the problem asks for a **subarray product** (e.g., "number of subarrays where product equals K"), the prefix sum pattern translates directly into a **Prefix Product**:
|
||||||
|
|
||||||
|
Product(i..j) = PrefixProduct[j] / PrefixProduct[i-1]
|
||||||
|
|
||||||
|
Instead of subtracting, you divide.
|
||||||
|
|
||||||
|
**Edge case:** Zeros reset the product to 0. Division by zero breaks the pattern. Handle by:
|
||||||
|
1. Segmentation — split the array at zeros, solve each segment independently
|
||||||
|
2. Track position of last seen zero to reset boundaries
|
||||||
|
|
||||||
|
* The Counter-Pattern: When Is It *Not* Prefix Sums?
|
||||||
|
|
||||||
|
While "subarray + sum" strongly hints at prefix sums, you need to look at the **constraints** and **types of numbers** to choose the absolute best tool.
|
||||||
|
|
||||||
|
| If you see "Subarray + Sum" AND... | The Real Pattern Is... | Why? |
|
||||||
|
|-------------------------------------------------------------------------------------------+--------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| All numbers are strictly positive (>= 0) and you need to find a target sum or max length. | **Sliding Window (Two Pointers)** | Because the window sum is monotonic (expanding always increases the sum; shrinking always decreases it). Sliding window optimizes space to O(1) compared to O(n) for prefix sums. |
|
||||||
|
| Numbers can be negative, or you need to find an exact target sum. | **Prefix Sum + Hash Map** | Monotonicity is broken. Adding an element could make the sum smaller, so sliding window fails. You *must* use a hash map to remember past states. |
|
||||||
|
| The array is **constantly being updated** (dynamic updates) between sum queries. | **Segment Tree or Fenwick Tree (BIT)** | A standard prefix sum array takes O(n) to update if an element changes. Segment/Fenwick trees drop update and query times to O(log n). |
|
||||||
|
|
||||||
|
* Generalizing the Concept: "Prefix State"
|
||||||
|
|
||||||
|
Don't limit this trick just to addition. The core philosophy of a prefix sum is **accumulating history as you traverse linearly**. You can use a hash map to track the "prefix state" for things that don't look like math at first.
|
||||||
|
|
||||||
|
| Problem | Mapping | Reduces To |
|
||||||
|
|-------------------------+------------------------------+----------------------------|
|
||||||
|
| Equal 0s and 1s | 0 → -1, 1 → +1 | Subarray sum = 0 |
|
||||||
|
| Equal odd/even | even → +1, odd → -1 | Subarray sum = 0 |
|
||||||
|
| Equal vowels/consonants | vowel → +1, consonant → -1 | Subarray sum = 0 |
|
||||||
|
| Equal A/B/C counts | Track (c_A - c_B, c_B - c_C) | Prefix state tuple repeats |
|
||||||
|
| Subarray product | Prefix product | Division (handle zeros) |
|
||||||
|
| Subarray XOR | Prefix XOR | XOR is invertible |
|
||||||
|
| Subarray sum | Prefix sum | Subtraction |
|
||||||
|
|
||||||
|
The pattern:
|
||||||
|
1. Define a state that accumulates as you traverse
|
||||||
|
2. Find a way to "undo" or compare states (subtract, XOR, divide, compare tuples)
|
||||||
|
3. Use a hash map to find when the same state (or target difference) appears
|
||||||
|
|
||||||
|
* Summary Checklist
|
||||||
|
|
||||||
|
1. Subarray + Sum + Negative Numbers → **Prefix Sum + Hash Map**
|
||||||
|
2. Subarray + Sum + Only Positive Numbers → **Sliding Window**
|
||||||
|
3. Subarray + Sum + Frequent Updates → **Segment/Fenwick Tree**
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
#+title: Segment Tree
|
||||||
|
|
||||||
|
* Segment
|
||||||
|
#+begin_src python
|
||||||
|
class seg_tree():
|
||||||
|
def __init__(self, arr):
|
||||||
|
self.n = len(arr)
|
||||||
|
self.t = [0]*self.n + arr
|
||||||
|
for i in range(self.n-1, -1, -1):
|
||||||
|
self.t[i] = self.t[i<<1] + self.t[(i<<1)+1]
|
||||||
|
|
||||||
|
def q(l, r):
|
||||||
|
|
||||||
|
class Fenwick:
|
||||||
|
def __init__(self, lst: List[int], lamd):
|
||||||
|
self.n = len(lst)
|
||||||
|
self.t = [0] * self.n + lst
|
||||||
|
print(self.t)
|
||||||
|
for i in range(self.n-1, 1, -1):
|
||||||
|
self.t[i] = self.t[i<<1] + self.t[(i<<1)+1]
|
||||||
|
self.f = lamd
|
||||||
|
|
||||||
|
def update(self, i, x):
|
||||||
|
i += self.n
|
||||||
|
self.t[i] = x
|
||||||
|
while i > 1:
|
||||||
|
self.t[i>>1] = self.t[i] + self.t[i^1]
|
||||||
|
i >>= 1
|
||||||
|
|
||||||
|
def query(self, lo, hi):
|
||||||
|
ans = 0
|
||||||
|
lo += self.n
|
||||||
|
hi += self.n
|
||||||
|
while lo < hi:
|
||||||
|
if lo & 1:
|
||||||
|
ans = min(ans, self.t[lo])
|
||||||
|
lo += 1
|
||||||
|
|
||||||
|
if hi & 1:
|
||||||
|
hi -= 1
|
||||||
|
ans = min(ans, self.t[hi])
|
||||||
|
lo >>= 1
|
||||||
|
hi >>= 1
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+begin_src python :results output
|
||||||
|
class Fenwick:
|
||||||
|
def __init__(self, lst: list[int]):
|
||||||
|
self.n = len(lst)
|
||||||
|
self.t = [float('inf')] * self.n + lst
|
||||||
|
for i in range(self.n-1, 1, -1):
|
||||||
|
self.t[i] = min(self.t[i<<1], self.t[(i<<1)+1])
|
||||||
|
print(self.t)
|
||||||
|
|
||||||
|
def update(self, i, x):
|
||||||
|
i += self.n
|
||||||
|
self.t[i] = x
|
||||||
|
while i > 1:
|
||||||
|
self.t[i>>1] = self.t[i] + self.t[i^1]
|
||||||
|
i >>= 1
|
||||||
|
|
||||||
|
def query(self, lo, hi):
|
||||||
|
ans = 0
|
||||||
|
lo += self.n
|
||||||
|
hi += self.n
|
||||||
|
while lo < hi:
|
||||||
|
if lo & 1:
|
||||||
|
ans = min(ans, self.t[lo])
|
||||||
|
lo += 1
|
||||||
|
|
||||||
|
if hi & 1:
|
||||||
|
hi -= 1
|
||||||
|
ans = min(ans, self.t[hi])
|
||||||
|
lo >>= 1
|
||||||
|
hi >>= 1
|
||||||
|
return ans
|
||||||
|
fw = Fenwick([999,2,1,999,999,999,999])
|
||||||
|
i = fw.query(0, 2)
|
||||||
|
print(i)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
: [inf, inf, 1, 999, 1, 999, 999, 999, 2, 1, 999, 999, 999, 999]
|
||||||
|
: 0
|
||||||
|
|
||||||
|
#+begin_src python :results output
|
||||||
|
class Fenwick:
|
||||||
|
def __init__(self, lst):
|
||||||
|
self.n = len(lst)
|
||||||
|
self.t = [float('inf')] * self.n + lst
|
||||||
|
for i in range(self.n - 1, 0, -1): # include root
|
||||||
|
self.t[i] = min(self.t[i<<1], self.t[(i<<1)+1])
|
||||||
|
|
||||||
|
def update(self, i, x):
|
||||||
|
i += self.n
|
||||||
|
self.t[i] = x
|
||||||
|
while i > 1:
|
||||||
|
self.t[i>>1] = min(self.t[i], self.t[i^1]) # min, not +
|
||||||
|
i >>= 1
|
||||||
|
|
||||||
|
def query(self, lo, hi):
|
||||||
|
ans = float('inf') # min identity
|
||||||
|
lo += self.n; hi += self.n
|
||||||
|
while lo < hi:
|
||||||
|
if lo & 1: ans = min(ans, self.t[lo]); lo += 1
|
||||||
|
if hi & 1: hi -= 1; ans = min(ans, self.t[hi])
|
||||||
|
lo >>= 1; hi >>= 1
|
||||||
|
return ans
|
||||||
|
fw = Fenwick([999,2,1,999,999,999,999])
|
||||||
|
i = fw.query(0, 3)
|
||||||
|
print(i)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
: 1
|
||||||
|
|
||||||
|
#+begin_src markdown
|
||||||
|
The code you provided is actually a *Segment Tree*, not a Fenwick Tree. It works by using a compact array representation of a complete binary tree to perform range minimum queries.
|
||||||
|
|
||||||
|
,*** 1. Structure
|
||||||
|
- *Array Layout:* For an input list of size $n$, it creates an array =t= of size $2n$.
|
||||||
|
,* Indices =n= to =2n-1= store the original elements (leaves).
|
||||||
|
,* Indices =1= to =n-1= store the minimum of their children (internal nodes).
|
||||||
|
- *Parent-Child Logic:* For any node at index =i=:
|
||||||
|
,* Left child: =i << 1= (or =2i=)
|
||||||
|
,* Right child: =(i << 1) + 1= (or =2i + 1=)
|
||||||
|
,* Parent: =i >> 1= (or =i // 2=)
|
||||||
|
|
||||||
|
,*** 2. Why it works
|
||||||
|
|
||||||
|
,**** Initialization (=__init__=)
|
||||||
|
It populates the leaves first, then iterates backwards from =n-1= down to =1=. This ensures that when calculating the minimum for node =i=, its children (=2i= and =2i+1=) have already been processed (or are leaves).
|
||||||
|
|
||||||
|
,**** Point Update (=update=)
|
||||||
|
1. Updates the leaf at =i + n=.
|
||||||
|
2. Moves up the tree (=i >>= 1=), re-calculating the minimum of the current node by comparing the updated node with its sibling (=i ^ 1=). This propagates the change up to the root in $O(\log n)$ time.
|
||||||
|
|
||||||
|
,**** Range Query (=query=)
|
||||||
|
This uses a "bottom-up" approach on the interval =[lo, hi)=:
|
||||||
|
1. If =lo= is a right child (=lo & 1=), it's the only child of its parent inside the range. We include it in the minimum and move to the next subtree (=lo += 1=).
|
||||||
|
2. If =hi= is a right child, the element at =hi-1= is inside the range. We include it and move left.
|
||||||
|
3. We then move both pointers to their parents (=>> 1=).
|
||||||
|
4. This collects only the "minimal" set of nodes covering the range in $O(\log n)$ time.
|
||||||
|
|
||||||
|
,*** Summary
|
||||||
|
While a *Fenwick Tree* (Binary Indexed Tree) is usually used for prefix sums and handles point updates in $O(\log n)$, it cannot efficiently perform range *minimum* queries for arbitrary ranges. This *Segment Tree* does exactly that by explicitly storing the minimum of power-of-two blocks.
|
||||||
|
|
||||||
|
,***
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
((org-mode . ((org-todo-keywords . ((sequence "TODO" | "DONE" "TOO_EASY")))
|
||||||
|
(eval . (let ((lc-el (expand-file-name "lc-org.el" (dir-locals-find-file default-directory))))
|
||||||
|
(when (and lc-el (file-exists-p lc-el))
|
||||||
|
(load-file lc-el)
|
||||||
|
(lc-org-mode 1)))))))
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
# study_deck_02
|
||||||
|
|
||||||
|
An Anki-exportable study deck for NeetCode DSA problems.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. **Roadmap** (`roadmap.org`) — the tracker. Lists all NeetCode 150 topics
|
||||||
|
and problems. Toggle `TODO` → `DONE` with `g c c` in Emacs as you
|
||||||
|
complete each one. Progress cookies (`[/]`) show topic completion.
|
||||||
|
|
||||||
|
2. **Notes** (`dsa/<topic>/<problem>.org`) — the real work. Each problem
|
||||||
|
has its own file with:
|
||||||
|
- Approach notes (write your own)
|
||||||
|
- Python and C++ solution stubs
|
||||||
|
- A `NEETCODE` property linking back to the roadmap
|
||||||
|
|
||||||
|
3. **Toolkit** (`toolkit/`) — your reference library:
|
||||||
|
- `tricks.org` — flashcards for patterns & tricks (exported to Anki)
|
||||||
|
- `notes.org` — deep implementation notes with explanations (exported to Anki)
|
||||||
|
- `suggestions.org` — pattern reference for quick lookup (not exported)
|
||||||
|
|
||||||
|
4. **Study flow** — open roadmap.org, pick a topic, pick a problem,
|
||||||
|
follow the Notes link, solve it, mark it DONE in both places.
|
||||||
|
|
||||||
|
## File Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
org/study_deck_02/
|
||||||
|
├── AGENTS.md ← you are here
|
||||||
|
├── roadmap.org ← generated by leetcode/extract.mjs
|
||||||
|
├── toolkit/
|
||||||
|
│ ├── tricks.org ← flashcards for patterns & tricks
|
||||||
|
│ ├── notes.org ← deep implementation notes
|
||||||
|
│ ├── suggestions.org ← pattern reference (not exported)
|
||||||
|
│ └── images/ ← diagrams, screenshots
|
||||||
|
└── dsa/
|
||||||
|
├── arrays-hashing/
|
||||||
|
│ ├── 0217-contains-duplicate.org
|
||||||
|
│ └── ...
|
||||||
|
├── two-pointers/
|
||||||
|
├── sliding-window/
|
||||||
|
├── linked-list/
|
||||||
|
├── binary-search/
|
||||||
|
├── stack/
|
||||||
|
├── trees/
|
||||||
|
├── tries/
|
||||||
|
├── heap-priority-queue/
|
||||||
|
├── backtracking/
|
||||||
|
├── graphs/
|
||||||
|
├── advanced-graphs/
|
||||||
|
├── 1-d-dynamic-programming/
|
||||||
|
├── 2-d-dynamic-programming/
|
||||||
|
├── greedy/
|
||||||
|
├── intervals/
|
||||||
|
├── math-geometry/
|
||||||
|
└── bit-manipulation/
|
||||||
|
```
|
||||||
|
|
||||||
|
18 topics, 199 problems (NeetCode 150).
|
||||||
|
|
||||||
|
## The `#+ANKI_DECK: study_deck_02` Header
|
||||||
|
|
||||||
|
Every `.org` file in this deck has `#+ANKI_DECK: study_deck_02` at the
|
||||||
|
top. This tells org-anki which Anki deck to export into. Without it,
|
||||||
|
the file won't be picked up by the exporter.
|
||||||
|
|
||||||
|
To override per-card, use `:ANKI_DECK:` in the properties drawer.
|
||||||
|
|
||||||
|
## Roadmap Format
|
||||||
|
|
||||||
|
Each problem in roadmap.org uses a properties drawer to keep links tidy:
|
||||||
|
|
||||||
|
```org
|
||||||
|
** TODO 0217. Contains Duplicate :easy:
|
||||||
|
:PROPERTIES:
|
||||||
|
:LEETCODE: [[https://leetcode.com/problems/contains-duplicate/][Problem]]
|
||||||
|
:CPP: [[https://github.com/neetcode-gh/leetcode/blob/main/cpp/0217-contains-duplicate.cpp][Solution]]
|
||||||
|
:PYTHON: [[https://github.com/neetcode-gh/leetcode/blob/main/python/0217-contains-duplicate.py][Solution]]
|
||||||
|
:VIDEO: [[https://youtube.com/watch?v=3OamzN90kPg][Watch]]
|
||||||
|
:END:
|
||||||
|
Notes: [[dsa/arrays-hashing/0217-contains-duplicate.org][My Solution]]
|
||||||
|
```
|
||||||
|
|
||||||
|
Properties are hidden by default in Emacs (`TAB` to cycle). The Notes
|
||||||
|
link is always visible — that's the one you click most.
|
||||||
|
|
||||||
|
## Notes Format
|
||||||
|
|
||||||
|
Each problem note links back to the roadmap via the `NEETCODE` property:
|
||||||
|
|
||||||
|
```org
|
||||||
|
* TODO 0217. Contains Duplicate :easy:
|
||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[../../roadmap.org::*0217. Contains Duplicate][Roadmap]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
```
|
||||||
|
|
||||||
|
## Regenerating
|
||||||
|
|
||||||
|
From the `leetcode/` directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node extract.mjs # fetches fresh data, writes roadmap.org here
|
||||||
|
node scaffold-notes.mjs # creates missing note files (skips existing)
|
||||||
|
```
|
||||||
|
|
||||||
|
Extract pulls from neetcode.io (cached in `leetcode/.cache/`). Scaffold
|
||||||
|
is idempotent — it only creates files that don't exist yet.
|
||||||
|
|
||||||
|
## Growing the Deck
|
||||||
|
|
||||||
|
This deck starts with NeetCode 150. To add more:
|
||||||
|
|
||||||
|
- **More problems** — edit `extract.mjs` to include `neetcode250` or
|
||||||
|
`blind75` flags, or remove the `neetcode150` filter entirely.
|
||||||
|
- **Custom topics** — add new folders under `dsa/`, create notes manually.
|
||||||
|
- **Other sources** — create new folders alongside `dsa/` (e.g.,
|
||||||
|
`euler/`, `advent-of-code/`) with the same `#+PROPERTY: STUDY_DECK_02`
|
||||||
|
header. They'll all export to the same Anki deck.
|
||||||
|
- **Flashcards** — add `** Front` / `** Back` sections to any note
|
||||||
|
for Anki-style cards (see root `AGENTS.md` for format).
|
||||||
|
|
||||||
|
## Backlinking Convention
|
||||||
|
|
||||||
|
Every `.org` file should link back to `roadmap.org` via a property:
|
||||||
|
|
||||||
|
- Problem notes use `:NEETCODE:` linking to the roadmap heading
|
||||||
|
- Toolkit/tricks use `:ROADMAP:` linking to a relevant problem
|
||||||
|
- Roadmap entries use `:TRICK:` linking to relevant tricks
|
||||||
|
|
||||||
|
This keeps the web of links navigable in both directions — from
|
||||||
|
roadmap to notes, from notes to tricks, and tricks back to problems.
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Add :lc-problem <number> to org source blocks in leetcode problem files."""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def process_file(path: Path, dry_run: bool = False) -> bool:
|
||||||
|
"""Add :lc-problem to src blocks that don't already have it. Returns True if modified."""
|
||||||
|
m = re.match(r"(\d{4})-", path.stem)
|
||||||
|
if not m:
|
||||||
|
return False
|
||||||
|
problem_num = str(int(m.group(1))) # strip leading zeros: "0015" -> "15"
|
||||||
|
|
||||||
|
text = path.read_text()
|
||||||
|
original = text
|
||||||
|
|
||||||
|
# Match #+begin_src <lang> where lang is python or cpp
|
||||||
|
def fix_src_block(match: re.Match) -> str:
|
||||||
|
full = match.group(0)
|
||||||
|
lang = match.group(1)
|
||||||
|
suffix = match.group(2) or ""
|
||||||
|
|
||||||
|
# If already has :lc-problem, fix leading zeros
|
||||||
|
if ":lc-problem" in suffix:
|
||||||
|
suffix = re.sub(r":lc-problem 0+(\d)", rf":lc-problem \1", suffix)
|
||||||
|
return f"#+begin_src {lang}{suffix}"
|
||||||
|
|
||||||
|
# Add :lc-problem
|
||||||
|
extra = f" :lc-problem {problem_num}"
|
||||||
|
if lang == "python":
|
||||||
|
extra += " :lc-lang python3"
|
||||||
|
return f"#+begin_src {lang}{extra}{suffix}"
|
||||||
|
|
||||||
|
text = re.sub(
|
||||||
|
r"#\+begin_src (python|cpp)([^\n]*)",
|
||||||
|
fix_src_block,
|
||||||
|
text,
|
||||||
|
)
|
||||||
|
|
||||||
|
if text != original:
|
||||||
|
if dry_run:
|
||||||
|
print(f" would modify: {path.name}")
|
||||||
|
else:
|
||||||
|
path.write_text(text)
|
||||||
|
print(f" modified: {path.name}")
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
dry_run = "--dry-run" in sys.argv
|
||||||
|
base = Path(__file__).parent / "dsa"
|
||||||
|
if not base.exists():
|
||||||
|
print(f"dsa/ directory not found at {base}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
org_files = sorted(base.rglob("*.org"))
|
||||||
|
print(f"Found {len(org_files)} org files in dsa/")
|
||||||
|
|
||||||
|
modified = 0
|
||||||
|
skipped = 0
|
||||||
|
for f in org_files:
|
||||||
|
if process_file(f, dry_run):
|
||||||
|
modified += 1
|
||||||
|
else:
|
||||||
|
skipped += 1
|
||||||
|
|
||||||
|
print(f"\nDone: {modified} modified, {skipped} unchanged")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0005. Longest Palindromic Substring :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0005. Longest Palindromic Substring][0005. Longest Palindromic Substring]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given a string ~s~, return /the longest/ /palindromic/ /substring/ in ~s~.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "babad"
|
||||||
|
Output: "bab"
|
||||||
|
Explanation: "aba" is also a valid answer.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "cbbd"
|
||||||
|
Output: "bb"
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= s.length <= 1000~
|
||||||
|
|
||||||
|
- ~s~ consist of only digits and English letters.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 5 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def longestPalindrome(self, s: str) -> str:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 5
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
string longestPalindrome(string s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0070. Climbing Stairs :easy:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0070. Climbing Stairs][0070. Climbing Stairs]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are climbing a staircase. It takes ~n~ steps to reach the top.
|
||||||
|
|
||||||
|
Each time you can either climb ~1~ or ~2~ steps. In how many distinct ways can you climb to the top?
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 2
|
||||||
|
Output: 2
|
||||||
|
Explanation: There are two ways to climb to the top.
|
||||||
|
1. 1 step + 1 step
|
||||||
|
2. 2 steps
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 3
|
||||||
|
Output: 3
|
||||||
|
Explanation: There are three ways to climb to the top.
|
||||||
|
1. 1 step + 1 step + 1 step
|
||||||
|
2. 1 step + 2 steps
|
||||||
|
3. 2 steps + 1 step
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= n <= 45~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 70 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def climbStairs(self, n: int) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 70
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int climbStairs(int n) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0091. Decode Ways :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0091. Decode Ways][0091. Decode Ways]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You have intercepted a secret message encoded as a string of numbers. The message is *decoded* via the following mapping:
|
||||||
|
|
||||||
|
~"1" -> 'A'
|
||||||
|
|
||||||
|
"2" -> 'B'
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
"25" -> 'Y'
|
||||||
|
|
||||||
|
"26" -> 'Z'~
|
||||||
|
|
||||||
|
However, while decoding the message, you realize that there are many different ways you can decode the message because some codes are contained in other codes (~"2"~ and ~"5"~ vs ~"25"~).
|
||||||
|
|
||||||
|
For example, ~"11106"~ can be decoded into:
|
||||||
|
|
||||||
|
- ~"AAJF"~ with the grouping ~(1, 1, 10, 6)~
|
||||||
|
|
||||||
|
- ~"KJF"~ with the grouping ~(11, 10, 6)~
|
||||||
|
|
||||||
|
- The grouping ~(1, 11, 06)~ is invalid because ~"06"~ is not a valid code (only ~"6"~ is valid).
|
||||||
|
|
||||||
|
Note: there may be strings that are impossible to decode.
|
||||||
|
|
||||||
|
Given a string s containing only digits, return the *number of ways* to *decode* it. If the entire string cannot be decoded in any valid way, return ~0~.
|
||||||
|
|
||||||
|
The test cases are generated so that the answer fits in a *32-bit* integer.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
*Input:* s = "12"
|
||||||
|
|
||||||
|
*Output:* 2
|
||||||
|
|
||||||
|
*Explanation:*
|
||||||
|
|
||||||
|
"12" could be decoded as "AB" (1 2) or "L" (12).
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
*Input:* s = "226"
|
||||||
|
|
||||||
|
*Output:* 3
|
||||||
|
|
||||||
|
*Explanation:*
|
||||||
|
|
||||||
|
"226" could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
*Input:* s = "06"
|
||||||
|
|
||||||
|
*Output:* 0
|
||||||
|
|
||||||
|
*Explanation:*
|
||||||
|
|
||||||
|
"06" cannot be mapped to "F" because of the leading zero ("6" is different from "06"). In this case, the string is not a valid encoding, so return 0.
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= s.length <= 100~
|
||||||
|
|
||||||
|
- ~s~ contains only digits and may contain leading zero(s).
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 91 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def numDecodings(self, s: str) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 91
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int numDecodings(string s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0139. Word Break :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0139. Word Break][0139. Word Break]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given a string ~s~ and a dictionary of strings ~wordDict~, return ~true~ if ~s~ can be segmented into a space-separated sequence of one or more dictionary words.
|
||||||
|
|
||||||
|
*Note* that the same word in the dictionary may be reused multiple times in the segmentation.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "leetcode", wordDict = ["leet","code"]
|
||||||
|
Output: true
|
||||||
|
Explanation: Return true because "leetcode" can be segmented as "leet code".
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "applepenapple", wordDict = ["apple","pen"]
|
||||||
|
Output: true
|
||||||
|
Explanation: Return true because "applepenapple" can be segmented as "apple pen apple".
|
||||||
|
Note that you are allowed to reuse a dictionary word.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "catsandog", wordDict = ["cats","dog","sand","and","cat"]
|
||||||
|
Output: false
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= s.length <= 300~
|
||||||
|
|
||||||
|
- ~1 <= wordDict.length <= 1000~
|
||||||
|
|
||||||
|
- ~1 <= wordDict[i].length <= 20~
|
||||||
|
|
||||||
|
- ~s~ and ~wordDict[i]~ consist of only lowercase English letters.
|
||||||
|
|
||||||
|
- All the strings of ~wordDict~ are *unique*.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 139 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 139
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
bool wordBreak(string s, vector<string>& wordDict) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0152. Maximum Product Subarray :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0152. Maximum Product Subarray][0152. Maximum Product Subarray]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an integer array ~nums~, find a subarray that has the largest product, and return /the product/.
|
||||||
|
|
||||||
|
The test cases are generated so that the answer will fit in a *32-bit* integer.
|
||||||
|
|
||||||
|
*Note* that the product of an array with a single element is the value of that element.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [2,3,-2,4]
|
||||||
|
Output: 6
|
||||||
|
Explanation: [2,3] has the largest product 6.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [-2,0,-1]
|
||||||
|
Output: 0
|
||||||
|
Explanation: The result cannot be 2, because [-2,-1] is not a subarray.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= nums.length <= 2 * 10^{4}~
|
||||||
|
|
||||||
|
- ~-10 <= nums[i] <= 10~
|
||||||
|
|
||||||
|
- The product of any subarray of ~nums~ is *guaranteed* to fit in a *32-bit* integer.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 152 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def maxProduct(self, nums: List[int]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 152
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int maxProduct(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0198. House Robber :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0198. House Robber][0198. House Robber]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security systems connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
|
||||||
|
|
||||||
|
Given an integer array ~nums~ representing the amount of money of each house, return /the maximum amount of money you can rob tonight without alerting the police/.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1,2,3,1]
|
||||||
|
Output: 4
|
||||||
|
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
|
||||||
|
Total amount you can rob = 1 + 3 = 4.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [2,7,9,3,1]
|
||||||
|
Output: 12
|
||||||
|
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
|
||||||
|
Total amount you can rob = 2 + 9 + 1 = 12.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= nums.length <= 100~
|
||||||
|
|
||||||
|
- ~0 <= nums[i] <= 400~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 198 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def rob(self, nums: List[int]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 198
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int rob(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0213. House Robber II :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0213. House Robber II][0213. House Robber II]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are *arranged in a circle.* That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have a security system connected, and it will automatically contact the police if two adjacent houses were broken into on the same night.
|
||||||
|
|
||||||
|
Given an integer array ~nums~ representing the amount of money of each house, return /the maximum amount of money you can rob tonight *without alerting the police*/.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [2,3,2]
|
||||||
|
Output: 3
|
||||||
|
Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2), because they are adjacent houses.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1,2,3,1]
|
||||||
|
Output: 4
|
||||||
|
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
|
||||||
|
Total amount you can rob = 1 + 3 = 4.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1,2,3]
|
||||||
|
Output: 3
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= nums.length <= 100~
|
||||||
|
|
||||||
|
- ~0 <= nums[i] <= 1000~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 213 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def rob(self, nums: List[int]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 213
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int rob(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0300. Longest Increasing Subsequence :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0300. Longest Increasing Subsequence][0300. Longest Increasing Subsequence]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an integer array ~nums~, return /the length of the longest *strictly increasing *//*subsequence*/.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [10,9,2,5,3,7,101,18]
|
||||||
|
Output: 4
|
||||||
|
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [0,1,0,3,2,3]
|
||||||
|
Output: 4
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [7,7,7,7,7,7,7]
|
||||||
|
Output: 1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= nums.length <= 2500~
|
||||||
|
|
||||||
|
- ~-10^{4} <= nums[i] <= 10^{4}~
|
||||||
|
|
||||||
|
Follow up: Can you come up with an algorithm that runs in ~O(n log(n))~ time complexity?
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 300 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def lengthOfLIS(self, nums: List[int]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 300
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int lengthOfLIS(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0322. Coin Change :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0322. Coin Change][0322. Coin Change]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given an integer array ~coins~ representing coins of different denominations and an integer ~amount~ representing a total amount of money.
|
||||||
|
|
||||||
|
Return /the fewest number of coins that you need to make up that amount/. If that amount of money cannot be made up by any combination of the coins, return ~-1~.
|
||||||
|
|
||||||
|
You may assume that you have an infinite number of each kind of coin.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: coins = [1,2,5], amount = 11
|
||||||
|
Output: 3
|
||||||
|
Explanation: 11 = 5 + 5 + 1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: coins = [2], amount = 3
|
||||||
|
Output: -1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: coins = [1], amount = 0
|
||||||
|
Output: 0
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= coins.length <= 12~
|
||||||
|
|
||||||
|
- ~1 <= coins[i] <= 2^{31} - 1~
|
||||||
|
|
||||||
|
- ~0 <= amount <= 10^{4}~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 322 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def coinChange(self, coins: List[int], amount: int) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 322
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int coinChange(vector<int>& coins, int amount) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0416. Partition Equal Subset Sum :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0416. Partition Equal Subset Sum][0416. Partition Equal Subset Sum]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an integer array ~nums~, return ~true~ /if you can partition the array into two subsets such that the sum of the elements in both subsets is equal or /~false~/ otherwise/.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1,5,11,5]
|
||||||
|
Output: true
|
||||||
|
Explanation: The array can be partitioned as [1, 5, 5] and [11].
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1,2,3,5]
|
||||||
|
Output: false
|
||||||
|
Explanation: The array cannot be partitioned into equal sum subsets.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= nums.length <= 200~
|
||||||
|
|
||||||
|
- ~1 <= nums[i] <= 100~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 416 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def canPartition(self, nums: List[int]) -> bool:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 416
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
bool canPartition(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0647. Palindromic Substrings :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0647. Palindromic Substrings][0647. Palindromic Substrings]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given a string ~s~, return /the number of *palindromic substrings* in it/.
|
||||||
|
|
||||||
|
A string is a *palindrome* when it reads the same backward as forward.
|
||||||
|
|
||||||
|
A *substring* is a contiguous sequence of characters within the string.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "abc"
|
||||||
|
Output: 3
|
||||||
|
Explanation: Three palindromic strings: "a", "b", "c".
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "aaa"
|
||||||
|
Output: 6
|
||||||
|
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= s.length <= 1000~
|
||||||
|
|
||||||
|
- ~s~ consists of lowercase English letters.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 647 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def countSubstrings(self, s: str) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 647
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int countSubstrings(string s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0656. Coin Path :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0656. Coin Path][0656. Coin Path]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 656 :lc-lang python3
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 656
|
||||||
|
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0746. Min Cost Climbing Stairs :easy:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0746. Min Cost Climbing Stairs][0746. Min Cost Climbing Stairs]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given an integer array ~cost~ where ~cost[i]~ is the cost of ~i^{th}~ step on a staircase. Once you pay the cost, you can either climb one or two steps.
|
||||||
|
|
||||||
|
You can either start from the step with index ~0~, or the step with index ~1~.
|
||||||
|
|
||||||
|
Return /the minimum cost to reach the top of the floor/.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: cost = [10,15,20]
|
||||||
|
Output: 15
|
||||||
|
Explanation: You will start at index 1.
|
||||||
|
- Pay 15 and climb two steps to reach the top.
|
||||||
|
The total cost is 15.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: cost = [1,100,1,1,1,100,1,1,100,1]
|
||||||
|
Output: 6
|
||||||
|
Explanation: You will start at index 0.
|
||||||
|
- Pay 1 and climb two steps to reach index 2.
|
||||||
|
- Pay 1 and climb two steps to reach index 4.
|
||||||
|
- Pay 1 and climb two steps to reach index 6.
|
||||||
|
- Pay 1 and climb one step to reach index 7.
|
||||||
|
- Pay 1 and climb two steps to reach index 9.
|
||||||
|
- Pay 1 and climb one step to reach the top.
|
||||||
|
The total cost is 6.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~2 <= cost.length <= 1000~
|
||||||
|
|
||||||
|
- ~0 <= cost[i] <= 999~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 746 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def minCostClimbingStairs(self, cost: List[int]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 746
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int minCostClimbingStairs(vector<int>& cost) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0010. Regular Expression Matching :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0010. Regular Expression Matching][0010. Regular Expression Matching]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an input string ~s~ and a pattern ~p~, implement regular expression matching with support for ~'.'~ and ~'*'~ where:
|
||||||
|
|
||||||
|
- ~'.'~ Matches any single character.
|
||||||
|
|
||||||
|
- ~'*'~ Matches zero or more of the preceding element.
|
||||||
|
|
||||||
|
Return a boolean indicating whether the matching covers the entire input string (not partial).
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "aa", p = "a"
|
||||||
|
Output: false
|
||||||
|
Explanation: "a" does not match the entire string "aa".
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "aa", p = "a*"
|
||||||
|
Output: true
|
||||||
|
Explanation: '*' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "ab", p = ".*"
|
||||||
|
Output: true
|
||||||
|
Explanation: ".*" means "zero or more (*) of any character (.)".
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= s.length <= 20~
|
||||||
|
|
||||||
|
- ~1 <= p.length <= 20~
|
||||||
|
|
||||||
|
- ~s~ contains only lowercase English letters.
|
||||||
|
|
||||||
|
- ~p~ contains only lowercase English letters, ~'.'~, and ~'*'~.
|
||||||
|
|
||||||
|
- It is guaranteed for each appearance of the character ~'*'~, there will be a previous valid character to match.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 10 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def isMatch(self, s: str, p: str) -> bool:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 10
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
bool isMatch(string s, string p) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0062. Unique Paths :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0062. Unique Paths][0062. Unique Paths]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
There is a robot on an ~m x n~ grid. The robot is initially located at the *top-left corner* (i.e., ~grid[0][0]~). The robot tries to move to the *bottom-right corner* (i.e., ~grid[m - 1][n - 1]~). The robot can only move either down or right at any point in time.
|
||||||
|
|
||||||
|
Given the two integers ~m~ and ~n~, return /the number of possible unique paths that the robot can take to reach the bottom-right corner/.
|
||||||
|
|
||||||
|
The test cases are generated so that the answer will be less than or equal to ~2 * 10^{9}~.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: m = 3, n = 7
|
||||||
|
Output: 28
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: m = 3, n = 2
|
||||||
|
Output: 3
|
||||||
|
Explanation: From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
|
||||||
|
1. Right -> Down -> Down
|
||||||
|
2. Down -> Down -> Right
|
||||||
|
3. Down -> Right -> Down
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= m, n <= 100~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 62 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def uniquePaths(self, m: int, n: int) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 62
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int uniquePaths(int m, int n) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0072. Edit Distance :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0072. Edit Distance][0072. Edit Distance]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given two strings ~word1~ and ~word2~, return /the minimum number of operations required to convert ~word1~ to ~word2~/.
|
||||||
|
|
||||||
|
You have the following three operations permitted on a word:
|
||||||
|
|
||||||
|
- Insert a character
|
||||||
|
|
||||||
|
- Delete a character
|
||||||
|
|
||||||
|
- Replace a character
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: word1 = "horse", word2 = "ros"
|
||||||
|
Output: 3
|
||||||
|
Explanation:
|
||||||
|
horse -> rorse (replace 'h' with 'r')
|
||||||
|
rorse -> rose (remove 'r')
|
||||||
|
rose -> ros (remove 'e')
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: word1 = "intention", word2 = "execution"
|
||||||
|
Output: 5
|
||||||
|
Explanation:
|
||||||
|
intention -> inention (remove 't')
|
||||||
|
inention -> enention (replace 'i' with 'e')
|
||||||
|
enention -> exention (replace 'n' with 'x')
|
||||||
|
exention -> exection (replace 'n' with 'c')
|
||||||
|
exection -> execution (insert 'u')
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~0 <= word1.length, word2.length <= 500~
|
||||||
|
|
||||||
|
- ~word1~ and ~word2~ consist of lowercase English letters.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 72 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def minDistance(self, word1: str, word2: str) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 72
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int minDistance(string word1, string word2) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0097. Interleaving String :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0097. Interleaving String][0097. Interleaving String]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given strings ~s1~, ~s2~, and ~s3~, find whether ~s3~ is formed by an *interleaving* of ~s1~ and ~s2~.
|
||||||
|
|
||||||
|
An *interleaving* of two strings ~s~ and ~t~ is a configuration where ~s~ and ~t~ are divided into ~n~ and ~m~ substrings respectively, such that:
|
||||||
|
|
||||||
|
- ~s = s_{1} + s_{2} + ... + s_{n}~
|
||||||
|
|
||||||
|
- ~t = t_{1} + t_{2} + ... + t_{m}~
|
||||||
|
|
||||||
|
- ~|n - m| <= 1~
|
||||||
|
|
||||||
|
- The *interleaving* is ~s_{1} + t_{1} + s_{2} + t_{2} + s_{3} + t_{3} + ...~ or ~t_{1} + s_{1} + t_{2} + s_{2} + t_{3} + s_{3} + ...~
|
||||||
|
|
||||||
|
*Note:* ~a + b~ is the concatenation of strings ~a~ and ~b~.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
|
||||||
|
Output: true
|
||||||
|
Explanation: One way to obtain s3 is:
|
||||||
|
Split s1 into s1 = "aa" + "bc" + "c", and s2 into s2 = "dbbc" + "a".
|
||||||
|
Interleaving the two splits, we get "aa" + "dbbc" + "bc" + "a" + "c" = "aadbbcbcac".
|
||||||
|
Since s3 can be obtained by interleaving s1 and s2, we return true.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
|
||||||
|
Output: false
|
||||||
|
Explanation: Notice how it is impossible to interleave s2 with any other string to obtain s3.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s1 = "", s2 = "", s3 = ""
|
||||||
|
Output: true
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~0 <= s1.length, s2.length <= 100~
|
||||||
|
|
||||||
|
- ~0 <= s3.length <= 200~
|
||||||
|
|
||||||
|
- ~s1~, ~s2~, and ~s3~ consist of lowercase English letters.
|
||||||
|
|
||||||
|
*Follow up:* Could you solve it using only ~O(s2.length)~ additional memory space?
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 97 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def isInterleave(self, s1: str, s2: str, s3: str) -> bool:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 97
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
bool isInterleave(string s1, string s2, string s3) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0115. Distinct Subsequences :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0115. Distinct Subsequences][0115. Distinct Subsequences]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given two strings s and t, return the number of distinct subsequences of s which equals t.
|
||||||
|
|
||||||
|
The test cases are generated so that the answer fits on a 32-bit signed integer.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "rabbbit", t = "rabbit"
|
||||||
|
Output: 3
|
||||||
|
Explanation:
|
||||||
|
As shown below, there are 3 ways you can generate "rabbit" from s.
|
||||||
|
rabbbit
|
||||||
|
rabbbit
|
||||||
|
rabbbit
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "babgbag", t = "bag"
|
||||||
|
Output: 5
|
||||||
|
Explanation:
|
||||||
|
As shown below, there are 5 ways you can generate "bag" from s.
|
||||||
|
babgbag
|
||||||
|
babgbag
|
||||||
|
babgbag
|
||||||
|
babgbag
|
||||||
|
babgbag
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= s.length, t.length <= 1000~
|
||||||
|
|
||||||
|
- ~s~ and ~t~ consist of English letters.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 115 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def numDistinct(self, s: str, t: str) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 115
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int numDistinct(string s, string t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0309. Best Time to Buy And Sell Stock With Cooldown :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0309. Best Time to Buy And Sell Stock With Cooldown][0309. Best Time to Buy And Sell Stock With Cooldown]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given an array ~prices~ where ~prices[i]~ is the price of a given stock on the ~i^{th}~ day.
|
||||||
|
|
||||||
|
Find the maximum profit you can achieve. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times) with the following restrictions:
|
||||||
|
|
||||||
|
- After you sell your stock, you cannot buy stock on the next day (i.e., cooldown one day).
|
||||||
|
|
||||||
|
*Note:* You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again).
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: prices = [1,2,3,0,2]
|
||||||
|
Output: 3
|
||||||
|
Explanation: transactions = [buy, sell, cooldown, buy, sell]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: prices = [1]
|
||||||
|
Output: 0
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= prices.length <= 5000~
|
||||||
|
|
||||||
|
- ~0 <= prices[i] <= 1000~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 309 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def maxProfit(self, prices: List[int]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 309
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int maxProfit(vector<int>& prices) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0312. Burst Balloons :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0312. Burst Balloons][0312. Burst Balloons]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given ~n~ balloons, indexed from ~0~ to ~n - 1~. Each balloon is painted with a number on it represented by an array ~nums~. You are asked to burst all the balloons.
|
||||||
|
|
||||||
|
If you burst the ~i^{th}~ balloon, you will get ~nums[i - 1] * nums[i] * nums[i + 1]~ coins. If ~i - 1~ or ~i + 1~ goes out of bounds of the array, then treat it as if there is a balloon with a ~1~ painted on it.
|
||||||
|
|
||||||
|
Return /the maximum coins you can collect by bursting the balloons wisely/.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [3,1,5,8]
|
||||||
|
Output: 167
|
||||||
|
Explanation:
|
||||||
|
nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> []
|
||||||
|
coins = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = 167
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1,5]
|
||||||
|
Output: 10
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~n == nums.length~
|
||||||
|
|
||||||
|
- ~1 <= n <= 300~
|
||||||
|
|
||||||
|
- ~0 <= nums[i] <= 100~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 312 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def maxCoins(self, nums: List[int]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 312
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int maxCoins(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0329. Longest Increasing Path In a Matrix :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0329. Longest Increasing Path In a Matrix][0329. Longest Increasing Path In a Matrix]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an ~m x n~ integers ~matrix~, return /the length of the longest increasing path in /~matrix~.
|
||||||
|
|
||||||
|
From each cell, you can either move in four directions: left, right, up, or down. You *may not* move *diagonally* or move *outside the boundary* (i.e., wrap-around is not allowed).
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: matrix = [[9,9,4],[6,6,8],[2,1,1]]
|
||||||
|
Output: 4
|
||||||
|
Explanation: The longest increasing path is [1, 2, 6, 9].
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: matrix = [[3,4,5],[3,2,6],[2,2,1]]
|
||||||
|
Output: 4
|
||||||
|
Explanation: The longest increasing path is [3, 4, 5, 6]. Moving diagonally is not allowed.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: matrix = [[1]]
|
||||||
|
Output: 1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~m == matrix.length~
|
||||||
|
|
||||||
|
- ~n == matrix[i].length~
|
||||||
|
|
||||||
|
- ~1 <= m, n <= 200~
|
||||||
|
|
||||||
|
- ~0 <= matrix[i][j] <= 2^{31} - 1~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 329 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 329
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int longestIncreasingPath(vector<vector<int>>& matrix) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0494. Target Sum :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0494. Target Sum][0494. Target Sum]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given an integer array ~nums~ and an integer ~target~.
|
||||||
|
|
||||||
|
You want to build an *expression* out of nums by adding one of the symbols ~'+'~ and ~'-'~ before each integer in nums and then concatenate all the integers.
|
||||||
|
|
||||||
|
- For example, if ~nums = [2, 1]~, you can add a ~'+'~ before ~2~ and a ~'-'~ before ~1~ and concatenate them to build the expression ~"+2-1"~.
|
||||||
|
|
||||||
|
Return the number of different *expressions* that you can build, which evaluates to ~target~.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1,1,1,1,1], target = 3
|
||||||
|
Output: 5
|
||||||
|
Explanation: There are 5 ways to assign symbols to make the sum of nums be target 3.
|
||||||
|
-1 + 1 + 1 + 1 + 1 = 3
|
||||||
|
+1 - 1 + 1 + 1 + 1 = 3
|
||||||
|
+1 + 1 - 1 + 1 + 1 = 3
|
||||||
|
+1 + 1 + 1 - 1 + 1 = 3
|
||||||
|
+1 + 1 + 1 + 1 - 1 = 3
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1], target = 1
|
||||||
|
Output: 1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= nums.length <= 20~
|
||||||
|
|
||||||
|
- ~0 <= nums[i] <= 1000~
|
||||||
|
|
||||||
|
- ~0 <= sum(nums[i]) <= 1000~
|
||||||
|
|
||||||
|
- ~-1000 <= target <= 1000~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 494 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def findTargetSumWays(self, nums: List[int], target: int) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 494
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int findTargetSumWays(vector<int>& nums, int target) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0518. Coin Change II :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0518. Coin Change II][0518. Coin Change II]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given an integer array ~coins~ representing coins of different denominations and an integer ~amount~ representing a total amount of money.
|
||||||
|
|
||||||
|
Return /the number of combinations that make up that amount/. If that amount of money cannot be made up by any combination of the coins, return ~0~.
|
||||||
|
|
||||||
|
You may assume that you have an infinite number of each kind of coin.
|
||||||
|
|
||||||
|
The answer is *guaranteed* to fit into a signed *32-bit* integer.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: amount = 5, coins = [1,2,5]
|
||||||
|
Output: 4
|
||||||
|
Explanation: there are four ways to make up the amount:
|
||||||
|
5=5
|
||||||
|
5=2+2+1
|
||||||
|
5=2+1+1+1
|
||||||
|
5=1+1+1+1+1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: amount = 3, coins = [2]
|
||||||
|
Output: 0
|
||||||
|
Explanation: the amount of 3 cannot be made up just with coins of 2.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: amount = 10, coins = [10]
|
||||||
|
Output: 1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= coins.length <= 300~
|
||||||
|
|
||||||
|
- ~1 <= coins[i] <= 5000~
|
||||||
|
|
||||||
|
- All the values of ~coins~ are *unique*.
|
||||||
|
|
||||||
|
- ~0 <= amount <= 5000~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 518 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def change(self, amount: int, coins: List[int]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 518
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int change(int amount, vector<int>& coins) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 1143. Longest Common Subsequence :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*1143. Longest Common Subsequence][1143. Longest Common Subsequence]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given two strings ~text1~ and ~text2~, return /the length of their longest *common subsequence*. /If there is no *common subsequence*, return ~0~.
|
||||||
|
|
||||||
|
A *subsequence* of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters.
|
||||||
|
|
||||||
|
- For example, ~"ace"~ is a subsequence of ~"abcde"~.
|
||||||
|
|
||||||
|
A *common subsequence* of two strings is a subsequence that is common to both strings.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: text1 = "abcde", text2 = "ace"
|
||||||
|
Output: 3
|
||||||
|
Explanation: The longest common subsequence is "ace" and its length is 3.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: text1 = "abc", text2 = "abc"
|
||||||
|
Output: 3
|
||||||
|
Explanation: The longest common subsequence is "abc" and its length is 3.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: text1 = "abc", text2 = "def"
|
||||||
|
Output: 0
|
||||||
|
Explanation: There is no such common subsequence, so the result is 0.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= text1.length, text2.length <= 1000~
|
||||||
|
|
||||||
|
- ~text1~ and ~text2~ consist of only lowercase English characters.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 1143 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 1143
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int longestCommonSubsequence(string text1, string text2) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 1220. Count Vowels Permutation :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*1220. Count Vowels Permutation][1220. Count Vowels Permutation]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an integer ~n~, your task is to count how many strings of length ~n~ can be formed under the following rules:
|
||||||
|
|
||||||
|
- Each character is a lower case vowel (~'a'~, ~'e'~, ~'i'~, ~'o'~, ~'u'~)
|
||||||
|
|
||||||
|
- Each vowel ~'a'~ may only be followed by an ~'e'~.
|
||||||
|
|
||||||
|
- Each vowel ~'e'~ may only be followed by an ~'a'~ or an ~'i'~.
|
||||||
|
|
||||||
|
- Each vowel ~'i'~ *may not* be followed by another ~'i'~.
|
||||||
|
|
||||||
|
- Each vowel ~'o'~ may only be followed by an ~'i'~ or a ~'u'~.
|
||||||
|
|
||||||
|
- Each vowel ~'u'~ may only be followed by an ~'a'~.
|
||||||
|
|
||||||
|
Since the answer may be too large, return it modulo ~10^9 + 7~.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 1
|
||||||
|
Output: 5
|
||||||
|
Explanation: All possible strings are: "a", "e", "i" , "o" and "u".
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 2
|
||||||
|
Output: 10
|
||||||
|
Explanation: All possible strings are: "ae", "ea", "ei", "ia", "ie", "io", "iu", "oi", "ou" and "ua".
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3: *
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 5
|
||||||
|
Output: 68
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= n <= 2 * 10^4~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 1220 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def countVowelPermutation(self, n: int) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 1220
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int countVowelPermutation(int n) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 1911. Maximum Alternating Subsequence Sum :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*1911. Maximum Alternating Subsequence Sum][1911. Maximum Alternating Subsequence Sum]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
The *alternating sum* of a *0-indexed* array is defined as the *sum* of the elements at *even* indices *minus* the *sum* of the elements at *odd* indices.
|
||||||
|
|
||||||
|
- For example, the alternating sum of ~[4,2,5,3]~ is ~(4 + 5) - (2 + 3) = 4~.
|
||||||
|
|
||||||
|
Given an array ~nums~, return /the *maximum alternating sum* of any subsequence of /~nums~/ (after *reindexing* the elements of the subsequence)/.
|
||||||
|
|
||||||
|
A *subsequence* of an array is a new array generated from the original array by deleting some elements (possibly none) without changing the remaining elements' relative order. For example, ~[2,7,4]~ is a subsequence of ~[4,2,3,7,2,1,4]~ (the underlined elements), while ~[2,4,2]~ is not.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [4,2,5,3]
|
||||||
|
Output: 7
|
||||||
|
Explanation: It is optimal to choose the subsequence [4,2,5] with alternating sum (4 + 5) - 2 = 7.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [5,6,7,8]
|
||||||
|
Output: 8
|
||||||
|
Explanation: It is optimal to choose the subsequence [8] with alternating sum 8.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [6,2,1,2,4,5]
|
||||||
|
Output: 10
|
||||||
|
Explanation: It is optimal to choose the subsequence [6,1,5] with alternating sum (6 + 5) - 1 = 10.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= nums.length <= 10^{5}~
|
||||||
|
|
||||||
|
- ~1 <= nums[i] <= 10^{5}~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 1911 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def maxAlternatingSum(self, nums: List[int]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 1911
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
long long maxAlternatingSum(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0269. Alien Dictionary :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0269. Alien Dictionary][0269. Alien Dictionary]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 269 :lc-lang python3
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 269
|
||||||
|
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0332. Reconstruct Itinerary :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0332. Reconstruct Itinerary][0332. Reconstruct Itinerary]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given a list of airline ~tickets~ where ~tickets[i] = [from_{i}, to_{i}]~ represent the departure and the arrival airports of one flight. Reconstruct the itinerary in order and return it.
|
||||||
|
|
||||||
|
All of the tickets belong to a man who departs from ~"JFK"~, thus, the itinerary must begin with ~"JFK"~. If there are multiple valid itineraries, you should return the itinerary that has the smallest lexical order when read as a single string.
|
||||||
|
|
||||||
|
- For example, the itinerary ~["JFK", "LGA"]~ has a smaller lexical order than ~["JFK", "LGB"]~.
|
||||||
|
|
||||||
|
You may assume all tickets form at least one valid itinerary. You must use all the tickets once and only once.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]
|
||||||
|
Output: ["JFK","MUC","LHR","SFO","SJC"]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
|
||||||
|
Output: ["JFK","ATL","JFK","SFO","ATL","SFO"]
|
||||||
|
Explanation: Another possible reconstruction is ["JFK","SFO","ATL","JFK","ATL","SFO"] but it is larger in lexical order.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= tickets.length <= 300~
|
||||||
|
|
||||||
|
- ~tickets[i].length == 2~
|
||||||
|
|
||||||
|
- ~from_{i}.length == 3~
|
||||||
|
|
||||||
|
- ~to_{i}.length == 3~
|
||||||
|
|
||||||
|
- ~from_{i}~ and ~to_{i}~ consist of uppercase English letters.
|
||||||
|
|
||||||
|
- ~from_{i} != to_{i}~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 332 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 332
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<string> findItinerary(vector<vector<string>>& tickets) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0743. Network Delay Time :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0743. Network Delay Time][0743. Network Delay Time]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given a network of ~n~ nodes, labeled from ~1~ to ~n~. You are also given ~times~, a list of travel times as directed edges ~times[i] = (u_{i}, v_{i}, w_{i})~, where ~u_{i}~ is the source node, ~v_{i}~ is the target node, and ~w_{i}~ is the time it takes for a signal to travel from source to target.
|
||||||
|
|
||||||
|
We will send a signal from a given node ~k~. Return /the *minimum* time it takes for all the/ ~n~ /nodes to receive the signal/. If it is impossible for all the ~n~ nodes to receive the signal, return ~-1~.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
|
||||||
|
Output: 2
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: times = [[1,2,1]], n = 2, k = 1
|
||||||
|
Output: 1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: times = [[1,2,1]], n = 2, k = 2
|
||||||
|
Output: -1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= k <= n <= 100~
|
||||||
|
|
||||||
|
- ~1 <= times.length <= 6000~
|
||||||
|
|
||||||
|
- ~times[i].length == 3~
|
||||||
|
|
||||||
|
- ~1 <= u_{i}, v_{i} <= n~
|
||||||
|
|
||||||
|
- ~u_{i} != v_{i}~
|
||||||
|
|
||||||
|
- ~0 <= w_{i} <= 100~
|
||||||
|
|
||||||
|
- All the pairs ~(u_{i}, v_{i})~ are *unique*. (i.e., no multiple edges.)
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 743 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 743
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int networkDelayTime(vector<vector<int>>& times, int n, int k) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0778. Swim In Rising Water :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0778. Swim In Rising Water][0778. Swim In Rising Water]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given an ~n x n~ integer matrix ~grid~ where each value ~grid[i][j]~ represents the elevation at that point ~(i, j)~.
|
||||||
|
|
||||||
|
It starts raining, and water gradually rises over time. At time ~t~, the water level is ~t~, meaning *any* cell with elevation less than equal to ~t~ is submerged or reachable.
|
||||||
|
|
||||||
|
You can swim from a square to another 4-directionally adjacent square if and only if the elevation of both squares individually are at most ~t~. You can swim infinite distances in zero time. Of course, you must stay within the boundaries of the grid during your swim.
|
||||||
|
|
||||||
|
Return /the minimum time until you can reach the bottom right square /~(n - 1, n - 1)~/ if you start at the top left square /~(0, 0)~.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: grid = [[0,2],[1,3]]
|
||||||
|
Output: 3
|
||||||
|
Explanation:
|
||||||
|
At time 0, you are in grid location (0, 0).
|
||||||
|
You cannot go anywhere else because 4-directionally adjacent neighbors have a higher elevation than t = 0.
|
||||||
|
You cannot reach point (1, 1) until time 3.
|
||||||
|
When the depth of water is 3, we can swim anywhere inside the grid.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: grid = [[0,1,2,3,4],[24,23,22,21,5],[12,13,14,15,16],[11,17,18,19,20],[10,9,8,7,6]]
|
||||||
|
Output: 16
|
||||||
|
Explanation: The final route is shown.
|
||||||
|
We need to wait until time 16 so that (0, 0) and (4, 4) are connected.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~n == grid.length~
|
||||||
|
|
||||||
|
- ~n == grid[i].length~
|
||||||
|
|
||||||
|
- ~1 <= n <= 50~
|
||||||
|
|
||||||
|
- ~0 <= grid[i][j] < n^{2}~
|
||||||
|
|
||||||
|
- Each value ~grid[i][j]~ is *unique*.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 778 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def swimInWater(self, grid: List[List[int]]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 778
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int swimInWater(vector<vector<int>>& grid) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0787. Cheapest Flights Within K Stops :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0787. Cheapest Flights Within K Stops][0787. Cheapest Flights Within K Stops]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
There are ~n~ cities connected by some number of flights. You are given an array ~flights~ where ~flights[i] = [from_{i}, to_{i}, price_{i}]~ indicates that there is a flight from city ~from_{i}~ to city ~to_{i}~ with cost ~price_{i}~.
|
||||||
|
|
||||||
|
You are also given three integers ~src~, ~dst~, and ~k~, return /*the cheapest price* from /~src~/ to /~dst~/ with at most /~k~/ stops. /If there is no such route, return/ /~-1~.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 4, flights = [[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]], src = 0, dst = 3, k = 1
|
||||||
|
Output: 700
|
||||||
|
Explanation:
|
||||||
|
The graph is shown above.
|
||||||
|
The optimal path with at most 1 stop from city 0 to 3 is marked in red and has cost 100 + 600 = 700.
|
||||||
|
Note that the path through cities [0,1,2,3] is cheaper but is invalid because it uses 2 stops.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 3, flights = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 1
|
||||||
|
Output: 200
|
||||||
|
Explanation:
|
||||||
|
The graph is shown above.
|
||||||
|
The optimal path with at most 1 stop from city 0 to 2 is marked in red and has cost 100 + 100 = 200.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 3, flights = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 0
|
||||||
|
Output: 500
|
||||||
|
Explanation:
|
||||||
|
The graph is shown above.
|
||||||
|
The optimal path with no stops from city 0 to 2 is marked in red and has cost 500.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~2 <= n <= 100~
|
||||||
|
|
||||||
|
- ~0 <= flights.length <= (n * (n - 1) / 2)~
|
||||||
|
|
||||||
|
- ~flights[i].length == 3~
|
||||||
|
|
||||||
|
- ~0 <= from_{i}, to_{i} < n~
|
||||||
|
|
||||||
|
- ~from_{i} != to_{i}~
|
||||||
|
|
||||||
|
- ~1 <= price_{i} <= 10^{4}~
|
||||||
|
|
||||||
|
- There will not be any multiple flights between two cities.
|
||||||
|
|
||||||
|
- ~0 <= src, dst, k < n~
|
||||||
|
|
||||||
|
- ~src != dst~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 787 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 787
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 1584. Min Cost to Connect All Points :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*1584. Min Cost to Connect All Points][1584. Min Cost to Connect All Points]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given an array ~points~ representing integer coordinates of some points on a 2D-plane, where ~points[i] = [x_{i}, y_{i}]~.
|
||||||
|
|
||||||
|
The cost of connecting two points ~[x_{i}, y_{i}]~ and ~[x_{j}, y_{j}]~ is the *manhattan distance* between them: ~|x_{i} - x_{j}| + |y_{i} - y_{j}|~, where ~|val|~ denotes the absolute value of ~val~.
|
||||||
|
|
||||||
|
Return /the minimum cost to make all points connected./ All points are connected if there is *exactly one* simple path between any two points.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: points = [[0,0],[2,2],[3,10],[5,2],[7,0]]
|
||||||
|
Output: 20
|
||||||
|
Explanation:
|
||||||
|
|
||||||
|
We can connect the points as shown above to get the minimum cost of 20.
|
||||||
|
Notice that there is a unique path between every pair of points.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: points = [[3,12],[-2,5],[-4,1]]
|
||||||
|
Output: 18
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= points.length <= 1000~
|
||||||
|
|
||||||
|
- ~-10^{6} <= x_{i}, y_{i} <= 10^{6}~
|
||||||
|
|
||||||
|
- All pairs ~(x_{i}, y_{i})~ are distinct.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 1584 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def minCostConnectPoints(self, points: List[List[int]]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 1584
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int minCostConnectPoints(vector<vector<int>>& points) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 2493. Divide Nodes Into the Maximum Number of Groups :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*2493. Divide Nodes Into the Maximum Number of Groups][2493. Divide Nodes Into the Maximum Number of Groups]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given a positive integer ~n~ representing the number of nodes in an *undirected* graph. The nodes are labeled from ~1~ to ~n~.
|
||||||
|
|
||||||
|
You are also given a 2D integer array ~edges~, where ~edges[i] = [a_{i, }b_{i}]~ indicates that there is a *bidirectional* edge between nodes ~a_{i}~ and ~b_{i}~. *Notice* that the given graph may be disconnected.
|
||||||
|
|
||||||
|
Divide the nodes of the graph into ~m~ groups (*1-indexed*) such that:
|
||||||
|
|
||||||
|
- Each node in the graph belongs to exactly one group.
|
||||||
|
|
||||||
|
- For every pair of nodes in the graph that are connected by an edge ~[a_{i, }b_{i}]~, if ~a_{i}~ belongs to the group with index ~x~, and ~b_{i}~ belongs to the group with index ~y~, then ~|y - x| = 1~.
|
||||||
|
|
||||||
|
Return /the maximum number of groups (i.e., maximum /~m~/) into which you can divide the nodes/. Return ~-1~ /if it is impossible to group the nodes with the given conditions/.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 6, edges = [[1,2],[1,4],[1,5],[2,6],[2,3],[4,6]]
|
||||||
|
Output: 4
|
||||||
|
Explanation: As shown in the image we:
|
||||||
|
- Add node 5 to the first group.
|
||||||
|
- Add node 1 to the second group.
|
||||||
|
- Add nodes 2 and 4 to the third group.
|
||||||
|
- Add nodes 3 and 6 to the fourth group.
|
||||||
|
We can see that every edge is satisfied.
|
||||||
|
It can be shown that that if we create a fifth group and move any node from the third or fourth group to it, at least on of the edges will not be satisfied.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 3, edges = [[1,2],[2,3],[3,1]]
|
||||||
|
Output: -1
|
||||||
|
Explanation: If we add node 1 to the first group, node 2 to the second group, and node 3 to the third group to satisfy the first two edges, we can see that the third edge will not be satisfied.
|
||||||
|
It can be shown that no grouping is possible.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= n <= 500~
|
||||||
|
|
||||||
|
- ~1 <= edges.length <= 10^{4}~
|
||||||
|
|
||||||
|
- ~edges[i].length == 2~
|
||||||
|
|
||||||
|
- ~1 <= a_{i}, b_{i} <= n~
|
||||||
|
|
||||||
|
- ~a_{i} != b_{i}~
|
||||||
|
|
||||||
|
- There is at most one edge between any pair of vertices.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 2493 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def magnificentSets(self, n: int, edges: List[List[int]]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 2493
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int magnificentSets(int n, vector<vector<int>>& edges) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 2812. Find the Safest Path in a Grid :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*2812. Find the Safest Path in a Grid][2812. Find the Safest Path in a Grid]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given a *0-indexed* 2D matrix ~grid~ of size ~n x n~, where ~(r, c)~ represents:
|
||||||
|
|
||||||
|
- A cell containing a thief if ~grid[r][c] = 1~
|
||||||
|
|
||||||
|
- An empty cell if ~grid[r][c] = 0~
|
||||||
|
|
||||||
|
You are initially positioned at cell ~(0, 0)~. In one move, you can move to any adjacent cell in the grid, including cells containing thieves.
|
||||||
|
|
||||||
|
The *safeness factor* of a path on the grid is defined as the *minimum* manhattan distance from any cell in the path to any thief in the grid.
|
||||||
|
|
||||||
|
Return /the *maximum safeness factor* of all paths leading to cell /~(n - 1, n - 1)~/./
|
||||||
|
|
||||||
|
An *adjacent* cell of cell ~(r, c)~, is one of the cells ~(r, c + 1)~, ~(r, c - 1)~, ~(r + 1, c)~ and ~(r - 1, c)~ if it exists.
|
||||||
|
|
||||||
|
The *Manhattan distance* between two cells ~(a, b)~ and ~(x, y)~ is equal to ~|a - x| + |b - y|~, where ~|val|~ denotes the absolute value of val.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: grid = [[1,0,0],[0,0,0],[0,0,1]]
|
||||||
|
Output: 0
|
||||||
|
Explanation: All paths from (0, 0) to (n - 1, n - 1) go through the thieves in cells (0, 0) and (n - 1, n - 1).
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: grid = [[0,0,1],[0,0,0],[0,0,0]]
|
||||||
|
Output: 2
|
||||||
|
Explanation: The path depicted in the picture above has a safeness factor of 2 since:
|
||||||
|
- The closest cell of the path to the thief at cell (0, 2) is cell (0, 0). The distance between them is | 0 - 0 | + | 0 - 2 | = 2.
|
||||||
|
It can be shown that there are no other paths with a higher safeness factor.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: grid = [[0,0,0,1],[0,0,0,0],[0,0,0,0],[1,0,0,0]]
|
||||||
|
Output: 2
|
||||||
|
Explanation: The path depicted in the picture above has a safeness factor of 2 since:
|
||||||
|
- The closest cell of the path to the thief at cell (0, 3) is cell (1, 2). The distance between them is | 0 - 1 | + | 3 - 2 | = 2.
|
||||||
|
- The closest cell of the path to the thief at cell (3, 0) is cell (3, 2). The distance between them is | 3 - 3 | + | 0 - 2 | = 2.
|
||||||
|
It can be shown that there are no other paths with a higher safeness factor.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= grid.length == n <= 400~
|
||||||
|
|
||||||
|
- ~grid[i].length == n~
|
||||||
|
|
||||||
|
- ~grid[i][j]~ is either ~0~ or ~1~.
|
||||||
|
|
||||||
|
- There is at least one thief in the ~grid~.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 2812 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def maximumSafenessFactor(self, grid: List[List[int]]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 2812
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int maximumSafenessFactor(vector<vector<int>>& grid) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0001. Two Sum :easy:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0001. Two Sum][0001. Two Sum]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an array of integers ~nums~ and an integer ~target~, return /indices of the two numbers such that they add up to ~target~/.
|
||||||
|
|
||||||
|
You may assume that each input would have */exactly/ one solution*, and you may not use the /same/ element twice.
|
||||||
|
|
||||||
|
You can return the answer in any order.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [2,7,11,15], target = 9
|
||||||
|
Output: [0,1]
|
||||||
|
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [3,2,4], target = 6
|
||||||
|
Output: [1,2]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [3,3], target = 6
|
||||||
|
Output: [0,1]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~2 <= nums.length <= 10^{4}~
|
||||||
|
|
||||||
|
- ~-10^{9} <= nums[i] <= 10^{9}~
|
||||||
|
|
||||||
|
- ~-10^{9} <= target <= 10^{9}~
|
||||||
|
|
||||||
|
- *Only one valid answer exists.*
|
||||||
|
|
||||||
|
*Follow-up: *Can you come up with an algorithm that is less than ~O(n^{2})~ time complexity?
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 1 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def twoSum(self, nums: List[int], target: int) -> List[int]:
|
||||||
|
sb = {}
|
||||||
|
for xi, x in enumerate(nums):
|
||||||
|
want = target - x;
|
||||||
|
if want in sb:
|
||||||
|
return sb[want], xi
|
||||||
|
sb[x] = xi
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 1
|
||||||
|
#include <algorithm>
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<int> twoSum(vector<int>& nums, int target) {
|
||||||
|
std::sort(nums.begin(), nums.end());
|
||||||
|
for (int i=0; i< nums.size(); i++) {
|
||||||
|
int x = nums[i];
|
||||||
|
if (x > target) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
// TODO: c++ binary search, i forgot how to do this
|
||||||
|
int want = target - x
|
||||||
|
auto it = std::binary_learch(nums.begin() + i + 1, nums.end(), want);
|
||||||
|
if (it != nums.end() && *it == want) {
|
||||||
|
int wi = std::distance(nums.begin(), it)
|
||||||
|
return {i, wi}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reuturn {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0036. Valid Sudoku :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0036. Valid Sudoku][0036. Valid Sudoku]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Determine if a ~9 x 9~ Sudoku board is valid. Only the filled cells need to be validated *according to the following rules*:
|
||||||
|
|
||||||
|
- Each row must contain the digits ~1-9~ without repetition.
|
||||||
|
|
||||||
|
- Each column must contain the digits ~1-9~ without repetition.
|
||||||
|
|
||||||
|
- Each of the nine ~3 x 3~ sub-boxes of the grid must contain the digits ~1-9~ without repetition.
|
||||||
|
|
||||||
|
*Note:*
|
||||||
|
|
||||||
|
- A Sudoku board (partially filled) could be valid but is not necessarily solvable.
|
||||||
|
|
||||||
|
- Only the filled cells need to be validated according to the mentioned rules.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: board =
|
||||||
|
[["5","3",".",".","7",".",".",".","."]
|
||||||
|
,["6",".",".","1","9","5",".",".","."]
|
||||||
|
,[".","9","8",".",".",".",".","6","."]
|
||||||
|
,["8",".",".",".","6",".",".",".","3"]
|
||||||
|
,["4",".",".","8",".","3",".",".","1"]
|
||||||
|
,["7",".",".",".","2",".",".",".","6"]
|
||||||
|
,[".","6",".",".",".",".","2","8","."]
|
||||||
|
,[".",".",".","4","1","9",".",".","5"]
|
||||||
|
,[".",".",".",".","8",".",".","7","9"]]
|
||||||
|
Output: true
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: board =
|
||||||
|
[["8","3",".",".","7",".",".",".","."]
|
||||||
|
,["6",".",".","1","9","5",".",".","."]
|
||||||
|
,[".","9","8",".",".",".",".","6","."]
|
||||||
|
,["8",".",".",".","6",".",".",".","3"]
|
||||||
|
,["4",".",".","8",".","3",".",".","1"]
|
||||||
|
,["7",".",".",".","2",".",".",".","6"]
|
||||||
|
,[".","6",".",".",".",".","2","8","."]
|
||||||
|
,[".",".",".","4","1","9",".",".","5"]
|
||||||
|
,[".",".",".",".","8",".",".","7","9"]]
|
||||||
|
Output: false
|
||||||
|
Explanation: Same as Example 1, except with the 5 in the top left corner being modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~board.length == 9~
|
||||||
|
|
||||||
|
- ~board[i].length == 9~
|
||||||
|
|
||||||
|
- ~board[i][j]~ is a digit ~1-9~ or ~'.'~.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 36 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def isValidSudoku(self, board: List[List[str]]) -> bool:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 36
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
bool isValidSudoku(vector<vector<char>>& board) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0049. Group Anagrams :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0049. Group Anagrams][0049. Group Anagrams]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an array of strings ~strs~, group the anagrams together. You can return the answer in *any order*.
|
||||||
|
|
||||||
|
*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.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 49 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 49
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<vector<string>> groupAnagrams(vector<string>& strs) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0128. Longest Consecutive Sequence :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0128. Longest Consecutive Sequence][0128. Longest Consecutive Sequence]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an unsorted array of integers ~nums~, return /the length of the longest consecutive elements sequence./
|
||||||
|
|
||||||
|
You must write an algorithm that runs in ~O(n)~ time.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [100,4,200,1,3,2]
|
||||||
|
Output: 4
|
||||||
|
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [0,3,7,2,5,8,4,6,0,1]
|
||||||
|
Output: 9
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1,0,1,2]
|
||||||
|
Output: 3
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~0 <= nums.length <= 10^{5}~
|
||||||
|
|
||||||
|
- ~-10^{9} <= nums[i] <= 10^{9}~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 128 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def longestConsecutive(self, nums: List[int]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 128
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int longestConsecutive(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* DONE 0217. Contains Duplicate :easy:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0217. Contains Duplicate][0217. Contains Duplicate]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
*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}~
|
||||||
|
|
||||||
|
** DONE Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** DONE Python
|
||||||
|
#+begin_src python :lc-problem 217 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def containsDuplicate(self, nums: List[int]) -> bool:
|
||||||
|
s = set()
|
||||||
|
for x in nums:
|
||||||
|
if x in s:
|
||||||
|
return True
|
||||||
|
s.add(x)
|
||||||
|
return False
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** DONE C++
|
||||||
|
#+begin_src cpp :lc-problem 217
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
bool containsDuplicate(std::vector<int>& nums) {
|
||||||
|
std::set<int> s;
|
||||||
|
for (int x: nums) {
|
||||||
|
if (s.contains(x)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
s.insert(x);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0238. Product of Array Except Self :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0238. Product of Array Except Self][0238. Product of Array Except Self]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
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]~.
|
||||||
|
|
||||||
|
The product of any prefix or suffix of ~nums~ is *guaranteed* to fit in a *32-bit* integer.
|
||||||
|
|
||||||
|
You must write an algorithm that runs in ~O(n)~ time and without using the division operation.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1,2,3,4]
|
||||||
|
Output: [24,12,8,6]
|
||||||
|
#+end_src
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [-1,1,0,-3,3]
|
||||||
|
Output: [0,0,9,0,0]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*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.
|
||||||
|
|
||||||
|
*Follow up:* Can you solve the problem in ~O(1)~ extra space complexity? (The output array *does not* count as extra space for space complexity analysis.)
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 238 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def productExceptSelf(self, nums: List[int]) -> List[int]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 238
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<int> productExceptSelf(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* DONE 0242. Valid Anagram :easy:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0242. Valid Anagram][0242. Valid Anagram]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given two strings ~s~ and ~t~, return ~true~ if ~t~ is an anagram of ~s~, and ~false~ otherwise.
|
||||||
|
|
||||||
|
*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.
|
||||||
|
|
||||||
|
*Follow up:* What if the inputs contain Unicode characters? How would you adapt your solution to such a case?
|
||||||
|
|
||||||
|
** DONE Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** DONE Python
|
||||||
|
#+begin_src python :lc-problem 242 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def isAnagram(self, s: str, t: str) -> bool:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** DONE C++
|
||||||
|
#+begin_src cpp :lc-problem 242
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
bool isAnagram(std::string s, std::string t) {
|
||||||
|
std::map<char, int> ctr;
|
||||||
|
for (char c: s) {
|
||||||
|
ctr[c] += c;
|
||||||
|
}
|
||||||
|
for (char c: t) {
|
||||||
|
if (ctr[c] == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ctr[c] -= 1;
|
||||||
|
if (ctr[c] == 0) {
|
||||||
|
ctr.erase(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctr.size() == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0271. Encode and Decode Strings :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0271. Encode and Decode Strings][0271. Encode and Decode Strings]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 271 :lc-lang python3
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 271
|
||||||
|
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0347. Top K Frequent Elements :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0347. Top K Frequent Elements][0347. Top K Frequent Elements]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an integer array ~nums~ and an integer ~k~, return /the/ ~k~ /most frequent elements/. You may return the answer in *any order*.
|
||||||
|
|
||||||
|
*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*.
|
||||||
|
|
||||||
|
*Follow up:* Your algorithm's time complexity must be better than ~O(n log n)~, where n is the array's size.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 347 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
|
||||||
|
from collections import Counter
|
||||||
|
return [n for n, _ in Counter(nums).most_common(k)]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 347
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<int> topKFrequent(vector<int>& nums, int k) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 1408. String Matching in an Array :easy:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*1408. String Matching in an Array][1408. String Matching in an Array]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an array of string ~words~, return all strings in/ /~words~/ /that are a substring of another word. You can return the answer in *any order*.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: words = ["mass","as","hero","superhero"]
|
||||||
|
Output: ["as","hero"]
|
||||||
|
Explanation: "as" is substring of "mass" and "hero" is substring of "superhero".
|
||||||
|
["hero","as"] is also a valid answer.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: words = ["leetcode","et","code"]
|
||||||
|
Output: ["et","code"]
|
||||||
|
Explanation: "et", "code" are substring of "leetcode".
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: words = ["blue","green","bu"]
|
||||||
|
Output: []
|
||||||
|
Explanation: No string of words is substring of another string.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= words.length <= 100~
|
||||||
|
|
||||||
|
- ~1 <= words[i].length <= 30~
|
||||||
|
|
||||||
|
- ~words[i]~ contains only lowercase English letters.
|
||||||
|
|
||||||
|
- All the strings of ~words~ are *unique*.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 1408 :lc-lang python3
|
||||||
|
from collections import defaultdict as dd
|
||||||
|
class Solution:
|
||||||
|
def stringMatching(self, words: List[str]) -> List[str]:
|
||||||
|
words = reversed(sorted(words))
|
||||||
|
def squash(word, trie):
|
||||||
|
lst = []
|
||||||
|
for c in word:
|
||||||
|
lst.append([trie, ''])
|
||||||
|
for i in range(len(lst)):
|
||||||
|
lst[i][0] = lst[i][0][c]
|
||||||
|
lst[i][1] += c
|
||||||
|
if not lst[i][0]['ads']:
|
||||||
|
lst[i][0]['ads'] = {lst[i][1]: [word]}
|
||||||
|
else:
|
||||||
|
lst[i][0]['ads'][lst[i][1]].append(word)
|
||||||
|
def in_trie(word, trie):
|
||||||
|
for c in word:
|
||||||
|
if c not in trie:
|
||||||
|
return []
|
||||||
|
trie = trie[c]
|
||||||
|
return [(word, bw) for bw in trie['ads'][word]]
|
||||||
|
trie_maker = lambda: dd(trie_maker)
|
||||||
|
trie = trie_maker()
|
||||||
|
ans = []
|
||||||
|
for s in words:
|
||||||
|
ans += in_trie(s, trie)
|
||||||
|
squash(s, trie)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 1408
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<string> stringMatching(vector<string>& words) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 1769. Minimum Number of Operations to Move All Balls to Each Box :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*1769. Minimum Number of Operations to Move All Balls to Each Box][1769. Minimum Number of Operations to Move All Balls to Each Box]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You have ~n~ boxes. You are given a binary string ~boxes~ of length ~n~, where ~boxes[i]~ is ~'0'~ if the ~i^{th}~ box is *empty*, and ~'1'~ if it contains *one* ball.
|
||||||
|
|
||||||
|
In one operation, you can move *one* ball from a box to an adjacent box. Box ~i~ is adjacent to box ~j~ if ~abs(i - j) == 1~. Note that after doing so, there may be more than one ball in some boxes.
|
||||||
|
|
||||||
|
Return an array ~answer~ of size ~n~, where ~answer[i]~ is the *minimum* number of operations needed to move all the balls to the ~i^{th}~ box.
|
||||||
|
|
||||||
|
Each ~answer[i]~ is calculated considering the *initial* state of the boxes.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: boxes = "110"
|
||||||
|
Output: [1,1,3]
|
||||||
|
Explanation: The answer for each box is as follows:
|
||||||
|
1) First box: you will have to move one ball from the second box to the first box in one operation.
|
||||||
|
2) Second box: you will have to move one ball from the first box to the second box in one operation.
|
||||||
|
3) Third box: you will have to move one ball from the first box to the third box in two operations, and move one ball from the second box to the third box in one operation.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: boxes = "001011"
|
||||||
|
Output: [11,8,5,4,3,4]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~n == boxes.length~
|
||||||
|
|
||||||
|
- ~1 <= n <= 2000~
|
||||||
|
|
||||||
|
- ~boxes[i]~ is either ~'0'~ or ~'1'~.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 1769 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def minOperations(self, boxes: str) -> List[int]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 1769
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<int> minOperations(string boxes) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 2678. Number of Senior Citizens :easy:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*2678. Number of Senior Citizens][2678. Number of Senior Citizens]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given a *0-indexed* array of strings ~details~. Each element of ~details~ provides information about a given passenger compressed into a string of length ~15~. The system is such that:
|
||||||
|
|
||||||
|
- The first ten characters consist of the phone number of passengers.
|
||||||
|
|
||||||
|
- The next character denotes the gender of the person.
|
||||||
|
|
||||||
|
- The following two characters are used to indicate the age of the person.
|
||||||
|
|
||||||
|
- The last two characters determine the seat allotted to that person.
|
||||||
|
|
||||||
|
Return /the number of passengers who are *strictly **more than 60 years old*./
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: details = ["7868190130M7522","5303914400F9211","9273338290F4010"]
|
||||||
|
Output: 2
|
||||||
|
Explanation: The passengers at indices 0, 1, and 2 have ages 75, 92, and 40. Thus, there are 2 people who are over 60 years old.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: details = ["1313579440F2036","2921522980M5644"]
|
||||||
|
Output: 0
|
||||||
|
Explanation: None of the passengers are older than 60.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= details.length <= 100~
|
||||||
|
|
||||||
|
- ~details[i].length == 15~
|
||||||
|
|
||||||
|
- ~details[i] consists of digits from '0' to '9'.~
|
||||||
|
|
||||||
|
- ~details[i][10] is either 'M' or 'F' or 'O'.~
|
||||||
|
|
||||||
|
- The phone numbers and seat numbers of the passengers are distinct.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 2678 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def countSeniors(self, details: List[str]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 2678
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int countSeniors(vector<string>& details) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0017. Letter Combinations of a Phone Number :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0017. Letter Combinations of a Phone Number][0017. Letter Combinations of a Phone Number]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given a string containing digits from ~2-9~ inclusive, return all possible letter combinations that the number could represent. Return the answer in *any order*.
|
||||||
|
|
||||||
|
A mapping of digits to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: digits = "23"
|
||||||
|
Output: ["ad","ae","af","bd","be","bf","cd","ce","cf"]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: digits = "2"
|
||||||
|
Output: ["a","b","c"]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= digits.length <= 4~
|
||||||
|
|
||||||
|
- ~digits[i]~ is a digit in the range ~['2', '9']~.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 17 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def letterCombinations(self, digits: str) -> List[str]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 17
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<string> letterCombinations(string digits) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0022. Generate Parentheses :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0022. Generate Parentheses][0022. Generate Parentheses]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given ~n~ pairs of parentheses, write a function to /generate all combinations of well-formed parentheses/.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 3
|
||||||
|
Output: ["((()))","(()())","(())()","()(())","()()()"]
|
||||||
|
#+end_src
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 1
|
||||||
|
Output: ["()"]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= n <= 8~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 22 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def generateParenthesis(self, n: int) -> List[str]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 22
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<string> generateParenthesis(int n) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0039. Combination Sum :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0039. Combination Sum][0039. Combination Sum]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an array of *distinct* integers ~candidates~ and a target integer ~target~, return /a list of all *unique combinations* of /~candidates~/ where the chosen numbers sum to /~target~/./ You may return the combinations in *any order*.
|
||||||
|
|
||||||
|
The *same* number may be chosen from ~candidates~ an *unlimited number of times*. Two combinations are unique if the frequency of at least one of the chosen numbers is different.
|
||||||
|
|
||||||
|
The test cases are generated such that the number of unique combinations that sum up to ~target~ is less than ~150~ combinations for the given input.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: candidates = [2,3,6,7], target = 7
|
||||||
|
Output: [[2,2,3],[7]]
|
||||||
|
Explanation:
|
||||||
|
2 and 3 are candidates, and 2 + 2 + 3 = 7. Note that 2 can be used multiple times.
|
||||||
|
7 is a candidate, and 7 = 7.
|
||||||
|
These are the only two combinations.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: candidates = [2,3,5], target = 8
|
||||||
|
Output: [[2,2,2,2],[2,3,3],[3,5]]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: candidates = [2], target = 1
|
||||||
|
Output: []
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= candidates.length <= 30~
|
||||||
|
|
||||||
|
- ~2 <= candidates[i] <= 40~
|
||||||
|
|
||||||
|
- All elements of ~candidates~ are *distinct*.
|
||||||
|
|
||||||
|
- ~1 <= target <= 40~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 39 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 39
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0040. Combination Sum II :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0040. Combination Sum II][0040. Combination Sum II]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given a collection of candidate numbers (~candidates~) and a target number (~target~), find all unique combinations in ~candidates~ where the candidate numbers sum to ~target~.
|
||||||
|
|
||||||
|
Each number in ~candidates~ may only be used *once* in the combination.
|
||||||
|
|
||||||
|
*Note:* The solution set must not contain duplicate combinations.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: candidates = [10,1,2,7,6,1,5], target = 8
|
||||||
|
Output:
|
||||||
|
[
|
||||||
|
[1,1,6],
|
||||||
|
[1,2,5],
|
||||||
|
[1,7],
|
||||||
|
[2,6]
|
||||||
|
]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: candidates = [2,5,2,1,2], target = 5
|
||||||
|
Output:
|
||||||
|
[
|
||||||
|
[1,2,2],
|
||||||
|
[5]
|
||||||
|
]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= candidates.length <= 100~
|
||||||
|
|
||||||
|
- ~1 <= candidates[i] <= 50~
|
||||||
|
|
||||||
|
- ~1 <= target <= 30~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 40 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 40
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0046. Permutations :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0046. Permutations][0046. Permutations]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an array ~nums~ of distinct integers, return all the possible permutations. You can return the answer in *any order*.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1,2,3]
|
||||||
|
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
|
||||||
|
#+end_src
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [0,1]
|
||||||
|
Output: [[0,1],[1,0]]
|
||||||
|
#+end_src
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1]
|
||||||
|
Output: [[1]]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= nums.length <= 6~
|
||||||
|
|
||||||
|
- ~-10 <= nums[i] <= 10~
|
||||||
|
|
||||||
|
- All the integers of ~nums~ are *unique*.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 46 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def permute(self, nums: List[int]) -> List[List[int]]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 46
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<vector<int>> permute(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0051. N Queens :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0051. N Queens][0051. N Queens]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
The *n-queens* puzzle is the problem of placing ~n~ queens on an ~n x n~ chessboard such that no two queens attack each other.
|
||||||
|
|
||||||
|
Given an integer ~n~, return /all distinct solutions to the *n-queens puzzle*/. You may return the answer in *any order*.
|
||||||
|
|
||||||
|
Each solution contains a distinct board configuration of the n-queens' placement, where ~'Q'~ and ~'.'~ both indicate a queen and an empty space, respectively.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 4
|
||||||
|
Output: [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
|
||||||
|
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 1
|
||||||
|
Output: [["Q"]]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= n <= 9~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 51 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def solveNQueens(self, n: int) -> List[List[str]]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 51
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<vector<string>> solveNQueens(int n) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0052. N Queens II :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0052. N Queens II][0052. N Queens II]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
The *n-queens* puzzle is the problem of placing ~n~ queens on an ~n x n~ chessboard such that no two queens attack each other.
|
||||||
|
|
||||||
|
Given an integer ~n~, return /the number of distinct solutions to the *n-queens puzzle*/.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 4
|
||||||
|
Output: 2
|
||||||
|
Explanation: There are two distinct solutions to the 4-queens puzzle as shown.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 1
|
||||||
|
Output: 1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= n <= 9~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 52 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def totalNQueens(self, n: int) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 52
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int totalNQueens(int n) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0077. Combinations :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0077. Combinations][0077. Combinations]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given two integers ~n~ and ~k~, return /all possible combinations of/ ~k~ /numbers chosen from the range/ ~[1, n]~.
|
||||||
|
|
||||||
|
You may return the answer in *any order*.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 4, k = 2
|
||||||
|
Output: [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
|
||||||
|
Explanation: There are 4 choose 2 = 6 total combinations.
|
||||||
|
Note that combinations are unordered, i.e., [1,2] and [2,1] are considered to be the same combination.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: n = 1, k = 1
|
||||||
|
Output: [[1]]
|
||||||
|
Explanation: There is 1 choose 1 = 1 total combination.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= n <= 20~
|
||||||
|
|
||||||
|
- ~1 <= k <= n~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 77 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def combine(self, n: int, k: int) -> List[List[int]]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 77
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<vector<int>> combine(int n, int k) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0078. Subsets :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0078. Subsets][0078. Subsets]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an integer array ~nums~ of *unique* elements, return /all possible/ /subsets/ /(the power set)/.
|
||||||
|
|
||||||
|
The solution set *must not* contain duplicate subsets. Return the solution in *any order*.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1,2,3]
|
||||||
|
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [0]
|
||||||
|
Output: [[],[0]]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= nums.length <= 10~
|
||||||
|
|
||||||
|
- ~-10 <= nums[i] <= 10~
|
||||||
|
|
||||||
|
- All the numbers of ~nums~ are *unique*.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 78 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def subsets(self, nums: List[int]) -> List[List[int]]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 78
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<vector<int>> subsets(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0079. Word Search :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0079. Word Search][0079. Word Search]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an ~m x n~ grid of characters ~board~ and a string ~word~, return ~true~ /if/ ~word~ /exists in the grid/.
|
||||||
|
|
||||||
|
The word can be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
|
||||||
|
Output: true
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
|
||||||
|
Output: true
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
|
||||||
|
Output: false
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~m == board.length~
|
||||||
|
|
||||||
|
- ~n = board[i].length~
|
||||||
|
|
||||||
|
- ~1 <= m, n <= 6~
|
||||||
|
|
||||||
|
- ~1 <= word.length <= 15~
|
||||||
|
|
||||||
|
- ~board~ and ~word~ consists of only lowercase and uppercase English letters.
|
||||||
|
|
||||||
|
*Follow up:* Could you use search pruning to make your solution faster with a larger ~board~?
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 79 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def exist(self, board: List[List[str]], word: str) -> bool:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 79
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
bool exist(vector<vector<char>>& board, string word) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0090. Subsets II :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0090. Subsets II][0090. Subsets II]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given an integer array ~nums~ that may contain duplicates, return /all possible/ /subsets// (the power set)/.
|
||||||
|
|
||||||
|
The solution set *must not* contain duplicate subsets. Return the solution in *any order*.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1,2,2]
|
||||||
|
Output: [[],[1],[1,2],[1,2,2],[2],[2,2]]
|
||||||
|
#+end_src
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [0]
|
||||||
|
Output: [[],[0]]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= nums.length <= 10~
|
||||||
|
|
||||||
|
- ~-10 <= nums[i] <= 10~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 90 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 90
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0131. Palindrome Partitioning :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0131. Palindrome Partitioning][0131. Palindrome Partitioning]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given a string ~s~, partition ~s~ such that every substring of the partition is a *palindrome*. Return /all possible palindrome partitioning of /~s~.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "aab"
|
||||||
|
Output: [["a","a","b"],["aa","b"]]
|
||||||
|
#+end_src
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: s = "a"
|
||||||
|
Output: [["a"]]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= s.length <= 16~
|
||||||
|
|
||||||
|
- ~s~ contains only lowercase English letters.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 131 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def partition(self, s: str) -> List[List[str]]:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 131
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<vector<string>> partition(string s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0351. Android Unlock Patterns :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0351. Android Unlock Patterns][0351. Android Unlock Patterns]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 351 :lc-lang python3
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 351
|
||||||
|
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 1079. Letter Tile Possibilities :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*1079. Letter Tile Possibilities][1079. Letter Tile Possibilities]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You have ~n~ ~tiles~, where each tile has one letter ~tiles[i]~ printed on it.
|
||||||
|
|
||||||
|
Return /the number of possible non-empty sequences of letters/ you can make using the letters printed on those ~tiles~.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: tiles = "AAB"
|
||||||
|
Output: 8
|
||||||
|
Explanation: The possible sequences are "A", "B", "AA", "AB", "BA", "AAB", "ABA", "BAA".
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: tiles = "AAABBC"
|
||||||
|
Output: 188
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: tiles = "V"
|
||||||
|
Output: 1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~1 <= tiles.length <= 7~
|
||||||
|
|
||||||
|
- ~tiles~ consists of uppercase English letters.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 1079 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def numTilePossibilities(self, tiles: str) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 1079
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int numTilePossibilities(string tiles) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 1863. Sum of All Subsets XOR Total :easy:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*1863. Sum of All Subsets XOR Total][Roadmap]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 1863 :lc-lang python3
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 1863
|
||||||
|
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0004. Median of Two Sorted Arrays :hard:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0004. Median of Two Sorted Arrays][0004. Median of Two Sorted Arrays]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Given two sorted arrays ~nums1~ and ~nums2~ of size ~m~ and ~n~ respectively, return *the median* of the two sorted arrays.
|
||||||
|
|
||||||
|
The overall run time complexity should be ~O(log (m+n))~.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums1 = [1,3], nums2 = [2]
|
||||||
|
Output: 2.00000
|
||||||
|
Explanation: merged array = [1,2,3] and median is 2.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums1 = [1,2], nums2 = [3,4]
|
||||||
|
Output: 2.50000
|
||||||
|
Explanation: merged array = [1,2,3,4] and median is (2 + 3) / 2 = 2.5.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~nums1.length == m~
|
||||||
|
|
||||||
|
- ~nums2.length == n~
|
||||||
|
|
||||||
|
- ~0 <= m <= 1000~
|
||||||
|
|
||||||
|
- ~0 <= n <= 1000~
|
||||||
|
|
||||||
|
- ~1 <= m + n <= 2000~
|
||||||
|
|
||||||
|
- ~-10^{6} <= nums1[i], nums2[i] <= 10^{6}~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 4 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 4
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0033. Search In Rotated Sorted Array :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0033. Search In Rotated Sorted Array][0033. Search In Rotated Sorted Array]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
There is an integer array ~nums~ sorted in ascending order (with *distinct* values).
|
||||||
|
|
||||||
|
Prior to being passed to your function, ~nums~ is *possibly left rotated* at an unknown index ~k~ (~1 <= k < nums.length~) such that the resulting array is ~[nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]~ (*0-indexed*). For example, ~[0,1,2,4,5,6,7]~ might be left rotated by ~3~ indices and become ~[4,5,6,7,0,1,2]~.
|
||||||
|
|
||||||
|
Given the array ~nums~ *after* the possible rotation and an integer ~target~, return /the index of /~target~/ if it is in /~nums~/, or /~-1~/ if it is not in /~nums~.
|
||||||
|
|
||||||
|
You must write an algorithm with ~O(log n)~ runtime complexity.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [4,5,6,7,0,1,2], target = 0
|
||||||
|
Output: 4
|
||||||
|
#+end_src
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [4,5,6,7,0,1,2], target = 3
|
||||||
|
Output: -1
|
||||||
|
#+end_src
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [1], target = 0
|
||||||
|
Output: -1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*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}~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 33 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def search(self, nums: List[int], target: int) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 33
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int search(vector<int>& nums, int target) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0074. Search a 2D Matrix :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0074. Search a 2D Matrix][0074. Search a 2D Matrix]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
You are given an ~m x n~ integer matrix ~matrix~ with the following two properties:
|
||||||
|
|
||||||
|
- Each row is sorted in non-decreasing order.
|
||||||
|
|
||||||
|
- The first integer of each row is greater than the last integer of the previous row.
|
||||||
|
|
||||||
|
Given an integer ~target~, return ~true~ /if/ ~target~ /is in/ ~matrix~ /or/ ~false~ /otherwise/.
|
||||||
|
|
||||||
|
You must write a solution in ~O(log(m * n))~ time complexity.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
|
||||||
|
Output: true
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
|
||||||
|
Output: false
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~m == matrix.length~
|
||||||
|
|
||||||
|
- ~n == matrix[i].length~
|
||||||
|
|
||||||
|
- ~1 <= m, n <= 100~
|
||||||
|
|
||||||
|
- ~-10^{4} <= matrix[i][j], target <= 10^{4}~
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 74 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 74
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
bool searchMatrix(vector<vector<int>>& matrix, int target) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0153. Find Minimum In Rotated Sorted Array :medium:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0153. Find Minimum In Rotated Sorted Array][0153. Find Minimum In Rotated Sorted Array]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Suppose an array of length ~n~ sorted in ascending order is *rotated* between ~1~ and ~n~ times. For example, the array ~nums = [0,1,2,4,5,6,7]~ might become:
|
||||||
|
|
||||||
|
- ~[4,5,6,7,0,1,2]~ if it was rotated ~4~ times.
|
||||||
|
|
||||||
|
- ~[0,1,2,4,5,6,7]~ if it was rotated ~7~ times.
|
||||||
|
|
||||||
|
Notice that *rotating* an array ~[a[0], a[1], a[2], ..., a[n-1]]~ 1 time results in the array ~[a[n-1], a[0], a[1], a[2], ..., a[n-2]]~.
|
||||||
|
|
||||||
|
Given the sorted rotated array ~nums~ of *unique* elements, return /the minimum element of this array/.
|
||||||
|
|
||||||
|
You must write an algorithm that runs in ~O(log n) time~.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [3,4,5,1,2]
|
||||||
|
Output: 1
|
||||||
|
Explanation: The original array was [1,2,3,4,5] rotated 3 times.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [4,5,6,7,0,1,2]
|
||||||
|
Output: 0
|
||||||
|
Explanation: The original array was [0,1,2,4,5,6,7] and it was rotated 4 times.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 3:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [11,13,15,17]
|
||||||
|
Output: 11
|
||||||
|
Explanation: The original array was [11,13,15,17] and it was rotated 4 times.
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Constraints:*
|
||||||
|
|
||||||
|
- ~n == nums.length~
|
||||||
|
|
||||||
|
- ~1 <= n <= 5000~
|
||||||
|
|
||||||
|
- ~-5000 <= nums[i] <= 5000~
|
||||||
|
|
||||||
|
- All the integers of ~nums~ are *unique*.
|
||||||
|
|
||||||
|
- ~nums~ is sorted and rotated between ~1~ and ~n~ times.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 153 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def findMin(self, nums: List[int]) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 153
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int findMin(vector<int>& nums) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#+ANKI_DECK: study_deck_02
|
||||||
|
* TODO 0704. Binary Search :easy:
|
||||||
|
:PROPERTIES:
|
||||||
|
:NEETCODE: [[file:../../roadmap.org::*0704. Binary Search][0704. Binary Search]]
|
||||||
|
:END:
|
||||||
|
|
||||||
|
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~.
|
||||||
|
|
||||||
|
You must write an algorithm with ~O(log n)~ runtime complexity.
|
||||||
|
|
||||||
|
*Example 1:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [-1,0,3,5,9,12], target = 9
|
||||||
|
Output: 4
|
||||||
|
Explanation: 9 exists in nums and its index is 4
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*Example 2:*
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src
|
||||||
|
Input: nums = [-1,0,3,5,9,12], target = 2
|
||||||
|
Output: -1
|
||||||
|
Explanation: 2 does not exist in nums so return -1
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*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.
|
||||||
|
|
||||||
|
** TODO Approach
|
||||||
|
Write your approach here.
|
||||||
|
|
||||||
|
** TODO Python
|
||||||
|
#+begin_src python :lc-problem 704 :lc-lang python3
|
||||||
|
class Solution:
|
||||||
|
def search(self, nums: List[int], target: int) -> int:
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** TODO C++
|
||||||
|
#+begin_src cpp :lc-problem 704
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int search(vector<int>& nums, int target) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user