Compare commits

...

35 Commits

Author SHA1 Message Date
tomatocream e10cc4257d add flashcard generation tooling and binary search cards
- gen-flashcards.py: auto-generate recognition cards from all problem files
- toolkit/gen-problem-cards.org: 199 auto-generated problem cards
- 5 binary search tool cards (std::binary_search, std::lower_bound, comparison, two-sum pattern, sorting gotcha)
- two-sum.org: add binary search C++ attempt
- lc-org.el: add doom emacs localleader keybinding support
2026-06-08 11:38:09 +08:00
tomatocream c67841fe07 upd 2026-06-08 11:38:09 +08:00
tomatocream 14d05011d5 upd 2026-06-08 11:38:09 +08:00
tomatocream 0aed1528e2 upd 2026-06-05 22:18:39 +08:00
tomatocream 0f9312eaee upd 2026-06-01 18:17:37 +08:00
tomatocream c9fe2fab76 feat: add TOO_EASY todo keyword via dir-locals
Sets org-todo-keywords for all files under org/study_deck_02/.
TOO_EASY counts as done in [/] checklist counters.
2026-06-01 17:50:05 +08:00
tomatocream 03561f8d10 update roadmap: mark 0217 Contains Duplicate as DONE 2026-06-01 17:36:33 +08:00
tomatocream fc6e664ff9 solve: 0217 Contains Duplicate (C++ set approach) 2026-06-01 17:36:12 +08:00
tomatocream 7659303fb0 docs: add populate-notes.mjs to leetcode/AGENTS.md 2026-06-01 17:36:12 +08:00
tomatocream cf158eafdf docs: add populate-notes.mjs to leetcode/AGENTS.md 2026-06-01 17:23:01 +08:00
tomatocream 1dec88aaf2 feat: populate note files with problem descriptions and code stubs
Add populate-notes.mjs that fetches problem descriptions and
Python/C++ code stubs from LeetCode's GraphQL API. Populated
all 197 NeetCode 150 note files with:
- Problem description (examples, constraints)
- Python code stub (function signature)
- C++ code stub (function signature + includes)

API responses cached in leetcode/.cache/leetcode/ for instant re-runs.
2026-06-01 17:22:07 +08:00
tomatocream e798e449bd fix: move #+PROPERTY: STUDY_DECK_02 to top of file
Org-mode requires global file properties before the first headline.
Moved PROPERTY line above the * TODO heading in all 199 note files
and updated scaffold-notes.mjs template.
2026-06-01 17:12:10 +08:00
tomatocream d674451070 fix: add file: prefix to org-mode links for Emacs resolution
Emorg org-mode requires [[file:path]] syntax for file links to be
clickable. Updated both extract.mjs and scaffold-notes.mjs generators,
and fixed all 200 existing note files.
2026-06-01 17:06:27 +08:00
tomatocream a50f4a121b fix: solution links in properties drawer, TODO sub-headings for tracking 2026-06-01 16:57:31 +08:00
tomatocream 1853f99367 fix: restore Python/C++ as TODO sub-headings in roadmap
Move CPP and PYTHON back to *** TODO sub-headings instead of
properties drawer entries. Remove [My Solution] from Notes links.
2026-06-01 16:55:51 +08:00
tomatocream 702213e83e remove solution 2026-06-01 16:53:12 +08:00
tomatocream dfadc1ca48 refactor: move DSA notes to org/study_deck_02/
Restructure NeetCode study materials into a dedicated Anki-exportable
deck directory. Separates DSA problem notes from C++ flashcards.

- Move roadmap.org from leetcode/out/ to org/study_deck_02/
- Move 200 note files from org/cpp/dsa/ to org/study_deck_02/dsa/
- Add #+PROPERTY: STUDY_DECK_02 to all org files for org-anki export
- Simplify roadmap format: properties drawer replaces nested headings
- Update NEETCODE backlinks in all note files
- Update extract.mjs and scaffold-notes.mjs for new paths
- Create org/study_deck_02/AGENTS.md with study workflow docs
- Update root and leetcode AGENTS.md
2026-06-01 16:12:21 +08:00
tomatocream 1d88296bf6 Expand progress cookies (org-mode auto-update) 2026-06-01 02:41:53 +08:00
tomatocream 956c2b2c88 Add TODO checkboxes to Python/C++ sub-headings
- roadmap.org: *** TODO Python and *** TODO C++ with [/] cookie
  on each problem heading for [0/2] progress tracking
- Note files now have TODO Approach, TODO Python, TODO C++
  sections for structured problem solving
2026-06-01 02:39:53 +08:00
tomatocream eabb433ec6 Add solution notes scaffold and sub-heading format
- roadmap.org: problems now have *** Python and *** C++ sub-headings,
  plus Notes: links to per-problem org files
- scaffold-notes.mjs: creates 199 note files in org/cpp/dsa/<topic>/
  with backlinks to roadmap.org
- 18 topic folders under org/cpp/dsa/ for NeetCode 150 problems
- Updated AGENTS.md with new conventions and workflow
2026-06-01 02:33:30 +08:00
tomatocream 7371b2617d Convert roadmap.org problems from list items to subheadings
Problems are now ** TODO headings with proper org tags (:easy:,
:medium:, :hard:) instead of checkbox list items. This enables
org-mode filtering by difficulty, proper subtree folding, and
automatic cookie updates on toggle.
2026-06-01 02:22:17 +08:00
tomatocream 142f2469ec docs: add AGENTS.md for leetcode extractor and update active context 2026-06-01 02:08:45 +08:00
tomatocream b4f25ab87b feat: add NeetCode roadmap extractor with dependency graph
- extract.mjs: idempotent script that fetches neetcode.io JS chunks,
  extracts topic dependency graph (18 topics, 21 edges) and problems
  (965 total, 199 NeetCode 150)
- out/roadmap.json: full data (graph + all problems + courses)
- out/roadmap-neetcode150.json: filtered to NeetCode 150 only
- out/roadmap.dot: Graphviz visualization
- out/roadmap.org: org-mode with TODO checklists, Python/C++ links
- neetcode-roadmap-graph.json: standalone edge list
- neetcode-roadmap.dot: standalone DOT file

Also reformats subarray table in qn_00.org
2026-06-01 02:07:20 +08:00
tomatocream f603236a48 Add remaining flashcards and reference files (qn_01, segment_tree, ds, learning) 2026-05-26 01:32:16 +08:00
tomatocream fa64e776ca Add subarray patterns reference guide (explanatory document) 2026-05-26 01:30:33 +08:00
tomatocream 127aad7003 Add prefix state generalization, product, bitwise, and keyword mappings 2026-05-26 01:28:42 +08:00
tomatocream defa2145e8 Convert LeetCode links to org-mode inline format 2026-05-26 01:19:43 +08:00
tomatocream 978ab00faa Add subarray sum equals K flashcards (LC 560, 974, 325) 2026-05-26 01:15:40 +08:00
tomatocream 3ab8ba001d feat: add UFDS flashcards and project learnings infrastructure 2026-05-04 09:01:42 +08:00
tomatocream 69676a84be upd 2026-05-04 08:12:20 +08:00
tomatocream 6b9a0d3161 feat: add std::deque flashcards covering all member functions 2026-05-04 00:27:49 +08:00
tomatocream eaed0664f3 update 2026-05-03 23:48:22 +08:00
tomatocream ffdbb39158 chore: sync Anki note IDs for arrays-and-refs flashcards
Adds ANKI_NOTE_ID properties after syncing cards to Anki deck.
Minor table alignment reformatting from the sync process.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 23:23:33 +08:00
tomatocream 09ce69a51a feat: add flashcards for std::array, references, and const parameters
Covers why raw arrays can't be returned, std::array vs int[] tradeoffs,
stack vs heap allocation, and const T& parameter conventions.
2026-04-22 01:46:03 +08:00
tomatocream dc6ab90c03 docs: add interview study plan for finance/HFT roles
Covers target firms, three study tracks (LeetCode, low-level systems,
system design), a 4-phase 12-week timeline, weekly rhythm, and resources.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 01:11:36 +08:00
247 changed files with 33450 additions and 0 deletions
+5
View File
@@ -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
+20
View File
@@ -31,3 +31,23 @@ code
## Self-Improvement
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`
+46
View File
@@ -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.
+40
View File
@@ -57,3 +57,43 @@ what is using?
we need to write binary search, lower bound search
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
+1
View File
@@ -0,0 +1 @@
.cache/
+118
View File
@@ -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`.
+372
View File
@@ -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);
});
+47
View File
@@ -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" }
]
}
+55
View File
@@ -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
+46
View File
@@ -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
+277
View File
@@ -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(/&lt;/g, "<")
.replace(/&gt;/g, ">")
.replace(/&amp;/g, "&")
.replace(/&nbsp;/g, " ")
.replace(/&quot;/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(/&lt;/g, "<");
text = text.replace(/&gt;/g, ">");
text = text.replace(/&amp;/g, "&");
text = text.replace(/&nbsp;/g, " ");
text = text.replace(/&quot;/g, '"');
text = text.replace(/&#39;/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);
});
+65
View File
@@ -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`);
+128
View File
@@ -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&~
+109
View File
@@ -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.
+396
View File
@@ -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
+3
View File
@@ -44,6 +44,9 @@ What are the four required operations for a C++ iterator?
** Front
List the five iterator categories in C++ (from simplest to most advanced)
** Back
:PROPERTIES:
:ANKI_NOTE_ID: 1777826854918
:END:
1. Input Iterator — read values, advance once
2. Output Iterator — write values, advance once
3. Forward Iterator — read/write, multiple passes
+219
View File
@@ -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.
+17
View File
@@ -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~.
+402
View File
@@ -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.
+77
View File
@@ -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
+763
View File
@@ -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
+268
View File
@@ -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
+67
View File
@@ -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**
+152
View File
@@ -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
+5
View File
@@ -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)))))))
+146
View File
@@ -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.
+74
View File
@@ -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: &#39;*&#39; means zero or more of the preceding element, &#39;a&#39;. Therefore, by repeating &#39;a&#39; 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 &#39;h&#39; with &#39;r&#39;)
rorse -> rose (remove &#39;r&#39;)
rose -> ros (remove &#39;e&#39;)
#+end_src
*Example 2:*
#+begin_src
Input: word1 = "intention", word2 = "execution"
Output: 5
Explanation:
intention -> inention (remove &#39;t&#39;)
inention -> enention (replace &#39;i&#39; with &#39;e&#39;)
enention -> exention (replace &#39;n&#39; with &#39;x&#39;)
exention -> exection (replace &#39;n&#39; with &#39;c&#39;)
exection -> execution (insert &#39;u&#39;)
#+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
@@ -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
@@ -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
@@ -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
@@ -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&#39;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
@@ -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