mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 13:12:44 +00:00
chore: clean up content phase organization
This commit is contained in:
1 parent
403a2d7f23
commit
bf0ac34a43
138 files changed
+1433
-365
No files matched your search
@@ -44,7 +44,7 @@ flowchart LR
|
||||
|---|---|
|
||||
| `work/<1\|3\|7>/<Difficulty>/<Category>/<num>.<slug>.{js,py}` | Solutions, e.g. `work/1/Easy/Array/1.two-sum.py`. The top directory is the spaced-repetition bucket: `1` = first solve, `3`/`7` = the blind re-solves of that problem 3 and 7 days later. Machine-parsed header comment (title / `Difficulty:` / URL / `─` rule / statement) — preserve its exact shape |
|
||||
| `apps/cli/` | Flat Bun TS workspace: automation entries (shebang + top-level await) and libraries (no shebang, side-effect-free on import). Root `bun run` scripts delegate here |
|
||||
| `apps/docs/` | Blume site (`blume.config.ts`, `content/`, `components/` + `components.ts`, `islands/`, `public/`). `content/<topic>/<num>-<slug>.mdx` plus one `meta.ts` per topic folder, all generated by sync: the folder is the README campaign topic slug (`tree-dfs/`, `heap-priority-queue/`) and a real route segment (`/tree-dfs/invert-binary-tree`), the `meta.ts` carries the exact label and topic number so the sidebar reads in curriculum order, and the page badge is the `work/` data-structure category. A hand-written `<topic>/index.mdx` (`hidden: true`) is that topic's landing page: Blume ≥ 1.7.3 links the sidebar group row to it (`sliding-window/index.mdx` → `/sliding-window`) and the hidden flag drops the duplicate row. Two kinds of custom MDX component, both import-free on every page: `islands/<Name>.tsx` is hydrated React (auto-discovered; `ProgressDashboard`, `DependencySpine` — the README topic map as data, zoom/pan, nodes link to whatever route Blume's `/api/docs/navigation.json` reports for the topic folder, inert until a topic has pages), `components/<Name>.astro` registered in `components.ts` is static markup plus a custom element for behaviour, the way Blume's own `Frame` is built (`Carousel`/`CarouselImage`: `src` takes a URL, `/file.png`, or the page-relative `../../public/file.png`) |
|
||||
| `apps/docs/` | Blume site (`blume.config.ts`, `content/`, `components/` + `components.ts`, `islands/`, `public/`). `content/(0N-<phase>)/<topic>/<num>-<slug>.mdx` plus one `meta.ts` per phase and per topic folder, all generated by sync: the phase folder is a `(group)` (sidebar section, no route segment), the topic folder is the README campaign topic slug (`tree-dfs/`, `heap-priority-queue/`) and a real route segment (`/tree-dfs/invert-binary-tree`), the `meta.ts` files carry the exact labels, phase/topic numbers and icons so the sidebar reads in curriculum order with each topic a collapsible group, and the page badge is the `work/` data-structure category. A hand-written `(0N-<phase>)/<topic>/index.mdx` (`hidden: true`) is that topic's landing page: Blume ≥ 1.7.3 links the sidebar group row to it (`sliding-window/index.mdx` → `/sliding-window`) and the hidden flag drops the duplicate row. Two kinds of custom MDX component, both import-free on every page: `islands/<Name>.tsx` is hydrated React (auto-discovered; `ProgressDashboard`, `DependencySpine` — the README topic map as data, zoom/pan, nodes link to whatever route Blume's `/api/docs/navigation.json` reports for the topic folder, inert until a topic has pages), `components/<Name>.astro` registered in `components.ts` is static markup plus a custom element for behaviour, the way Blume's own `Frame` is built (`Carousel`/`CarouselImage`: `src` takes a URL, `/file.png`, or the page-relative `../../public/file.png`) |
|
||||
| `apps/api/` | Cloudflare Worker workspace: `src/` modules, `data/schedule.json` (the plan: `date → { topics | problems | gate | sweep }`, human-edited, bundled at deploy), `migrations/` (append-only; `0002` is the +3/+7 ladder rebuild) |
|
||||
| `.github/workflows/` | deploy (docs → Pages, Worker → Cloudflare, on every main push), close-solved (issues + `/admin/solved` + Project `Set`/`Difficulty`, needs `SRS_ADMIN_KEY` and `PROJECT_PAT`), close-topics, sync-d1 (issue edits → `/admin/reconcile`), spaced-repetition (daily 06:00 ET cron → today's review issue; `GITHUB_TOKEN` only, no secrets) |
|
||||
| `.githooks/` | Tracked git hooks; `bun install` points `core.hooksPath` here (root `prepare` script, no husky). `pre-commit` runs `bun run sync` and stages only the pages sync changed, so a solution and its page land in one commit; it refuses to run while `work/1` has anything unstaged (sync reads the tree, so the page would not match the commit), and leaves pre-existing dirt under `apps/docs/content` (in-progress `## Approach` prose) unstaged. `git commit --no-verify` for a deliberate partial commit |
|
||||
@@ -106,11 +106,11 @@ curl -X POST -H "Authorization: Bearer $LINK_KEY" \
|
||||
- `apps/api/src/index.ts` — router + cron dispatch; `apps/api/wrangler.jsonc` — bindings (`DB`, `EMAIL`), crons, vars; secrets `GH_PAT`/`WEBHOOK_SECRET`/`LINK_KEY` via `wrangler secret put`.
|
||||
- `apps/api/src/digest.ts` / `apps/api/src/email.tsx` — the daily digest, split data/presentation. `digest.ts` reads D1 into a `DigestData`; `email.tsx` owns every colour and every sentence, and renders both the HTML and (via its own `plainDigest`, not React Email's `plainText` mode, which flattens the tables) the text alternative. The retrieval rules hold by construction: `DigestRow` has no title and no issue field, so a review or drill line *cannot* leak the topic or a solution link. Subject is `(Day N/56) LeetCode Daily Digest`.
|
||||
- `apps/api/src/png.ts` — hand-rolled PNG encoder (RGB8, one IDAT, zlib via `CompressionStream("deflate")`, CRC32, 5×7 bitmap font). It exists because every major email client refuses remote SVG, so `/chart/heatmap.png` rasters the heatmap for the digest while `/chart/heatmap.svg` keeps serving the README byte-for-byte. Both come from one `heatmapCells()` so the two pictures cannot drift.
|
||||
- `apps/cli/sync.ts` — work→docs contract: on existing pages only the `<Badge>` line and the `## Solution` section are script-owned, the latter bounded by `solutionEnd()` at the next unfenced top-level heading; human prose before it and any sections after it are never touched. Never hand-write solution pages or edit inside `## Solution`. Two classifications, two homes: the sidebar group is the README topic (`readmeTopics()`, first listing wins for a problem under two topics; a warm-up outside the plan groups under its category at `order: 0`, ahead of topic 1) and the badge is the `work/1/<Difficulty>/<Category>/` category — topic folders and their `meta.ts` are rewritten every run, a page is `rename`d when its topic changes, and a folder every page has left is deleted unless it still holds a hand-written `index.mdx` (sync never writes, moves, or deletes one). Never use `(group)` folders here: they add no route segment, so a topic `index.mdx` inside one collides with the root `/`. The two hand-owned sections around the solution have their own owners: `## Approach` (a Mermaid flowchart tracing the page's code, placed *before* `## Solution` so a re-sync keeps it) is written per the `problem-approach` skill (`/problem-approach` fills every page missing one); `## Explanation` (the NeetCode `<YouTube>` embed, after `## Solution`) is appended by `bun run videos --write` (`apps/cli/videos.ts`).
|
||||
- `apps/cli/sync.ts` — work→docs contract: on existing pages only the `<Badge>` line and the `## Solution` section are script-owned, the latter bounded by `solutionEnd()` at the next unfenced top-level heading; human prose before it and any sections after it are never touched. Never hand-write solution pages or edit inside `## Solution`. Two classifications, two homes: the sidebar group is the README topic (`readmeTopics()`, first listing wins for a problem under two topics; a warm-up outside the plan groups under its category at `order: 0`, ahead of topic 1) and the badge is the `work/1/<Difficulty>/<Category>/` category. Topics nest under their README phase (`## Phase N — Name` headings, shortened via `PHASE_ALIASES`): `content/(0N-<phase>)/<topic>/`, both `meta.ts` script-owned and rewritten every run (phase: `Phase N: Name`, `order: N`; topic: label, curriculum order, `TOPIC_ICONS` icon, `display: "group"`). The phase folder is a Blume `(group)` — no route segment, so `/tree-dfs` is unchanged and a landing page there is one level deep, never at `/` — and the topic folder is the real segment; never put a topic `index.mdx` directly inside a `(group)`. A page is `rename`d when its topic or phase changes; a folder every page has left is deleted (climbing into an emptied phase folder) unless it still holds a hand-written `index.mdx` (sync never writes, moves, or deletes one — so page-relative asset paths in a moved landing page are yours to fix). Slugs come from `slugify()`, which glues a leading number to the next token (`1d-dynamic-programming`) because Blume strips `<digits>-` prefixes from routes. The two hand-owned sections around the solution have their own owners: `## Approach` (a Mermaid flowchart tracing the page's code, placed *before* `## Solution` so a re-sync keeps it) is written per the `problem-approach` skill (`/problem-approach` fills every page missing one); `## Explanation` (the NeetCode `<YouTube>` embed, after `## Solution`) is appended by `bun run videos --write` (`apps/cli/videos.ts`).
|
||||
- `apps/cli/work.ts` — the `work/` layout: bucket paths, `isSolution()`/`solvedInBucket()` (the stub test, shared with `close-solved.ts`), `firstSolved()` (one `git log`, ET dates, keyed by LC number so past layout moves don't matter), and `reviewQueues()` (what each window still owes). Everything that needs to know where a solution file lives, or when it was solved, goes through here.
|
||||
- `apps/api/src/stats.ts` / `apps/cli/stats.ts` / `apps/cli/tui.ts` / `apps/cli/api.ts` — the read side. `buildStats()` is the ONE aggregation: phases, ladder, difficulty, per-topic temperature, gates, the 14-day due queue, and `heat` (every campaign day, zeros and future days included — the docs page windows the tail off it rather than asking a second question). Two readers consume it, the docs island and `bun run stats`, so its shape is both their contract: change all three together. `tui.ts` is hand-rolled ANSI (bars, sparklines, heat cells, alternate screen) on charts.ts's palette, and every chart differs by GLYPH as well as by colour so a piped or `NO_COLOR` dashboard still reads. The TUI recomputes nothing: the only local fact it shows is the `work/` solution count, which is inventory, not schedule.
|
||||
- `README.md` live charts are Worker endpoints (`/chart/*.svg`, `/badge/gate.svg`, 5-min Camo cache); the docs `/progress` page fetches `/api/stats` client-side (`apps/docs/islands/ProgressDashboard.tsx`).
|
||||
- `apps/docs/blume.config.ts` — site base `/leetcode`; `README.md` campaign table doubles as topic-map input to `sync.ts` (`readmeTopics()`, `TOPIC_ALIASES`).
|
||||
- `apps/docs/blume.config.ts` — site base `/leetcode`; `README.md` campaign table doubles as topic-map input to `sync.ts` (`readmeTopics()`, `TOPIC_ALIASES`, `PHASE_ALIASES`).
|
||||
- Old `.github/srs/` JSON state, its `srs-*` Actions, and the one-shot `import-srs.ts` importer are RETIRED and deleted — do not resurrect; git history is the record.
|
||||
|
||||
## Runtime/Tooling Preferences
|
||||
|
||||
+109
-36
@@ -17,11 +17,14 @@
|
||||
* file sits under in `work/1/<Difficulty>/<Category>/`. A problem outside the
|
||||
* plan (warm-ups) has no topic, so it groups under its category instead.
|
||||
*
|
||||
* Topic folders are real route segments (`/tree-dfs/invert-binary-tree`), not
|
||||
* `(group)` folders, so a hand-written `index.mdx` in one is the topic's
|
||||
* landing page at `/tree-dfs` and Blume links the sidebar group row to it.
|
||||
* Sync never writes or moves an `index.mdx`, and never removes a folder that
|
||||
* still holds one.
|
||||
* Topics nest under their README PHASE: `(01-linear-structures)/tree-dfs/`.
|
||||
* The phase folder is a Blume `(group)` — a sidebar section with its own
|
||||
* script-owned `meta.ts`, adding no route segment — while the topic folder is
|
||||
* a real segment (`/tree-dfs/invert-binary-tree`), so a hand-written
|
||||
* `index.mdx` in it is the topic's landing page at `/tree-dfs` and Blume links
|
||||
* the sidebar group row to it. Sync never writes or moves an `index.mdx`, and
|
||||
* never removes a folder that still holds one. An unplanned category group has
|
||||
* no phase and sits at the content root.
|
||||
*
|
||||
* Only the first-solve bucket is read: work/3 and work/7 hold blind re-solves
|
||||
* of problems whose page already exists (see work.ts), and a fresh scaffold
|
||||
@@ -171,12 +174,29 @@ function parseHeader(header: string): Header {
|
||||
|
||||
// ── README topic map ─────────────────────────────────────────────
|
||||
|
||||
/** A campaign phase: `## Phase N — Name · Weeks …` in the README. */
|
||||
interface Phase {
|
||||
order: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/** A campaign topic: `<strong>NN. Name</strong>` in the README table. */
|
||||
interface Topic {
|
||||
order?: number; // README topic number; absent for an unplanned problem's category group
|
||||
name: string;
|
||||
phase?: Phase; // absent for an unplanned category group
|
||||
}
|
||||
|
||||
/** README phase names → the short labels the overview page uses. */
|
||||
const PHASE_ALIASES: Record<string, string> = {
|
||||
"Nodal & Grid Structures": "Nodal & Grid",
|
||||
"Hierarchical Structures": "Hierarchical",
|
||||
"Relational Structures": "Relational",
|
||||
"Decision-Space Exploration": "Decision Space",
|
||||
};
|
||||
|
||||
const ROMAN = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"];
|
||||
|
||||
const TOPIC_ALIASES: Record<string, string> = {
|
||||
"Hash-Based Lookup": "Hash Table",
|
||||
};
|
||||
@@ -224,10 +244,16 @@ const TOPIC_ICONS: Record<string, string> = {
|
||||
async function readmeTopics(): Promise<Map<number, Topic>> {
|
||||
const md = await Bun.file(join(ROOT, "README.md")).text();
|
||||
const map = new Map<number, Topic>();
|
||||
let phase: Phase | undefined;
|
||||
let topic: Topic | null = null;
|
||||
for (const line of md.split("\n")) {
|
||||
const p = line.match(/^## Phase ([IVX]+) — (.+?) · /);
|
||||
if (p) {
|
||||
const name = p[2]!.replaceAll("&", "&");
|
||||
phase = { order: ROMAN.indexOf(p[1]!) + 1, name: PHASE_ALIASES[name] ?? name };
|
||||
}
|
||||
const t = line.match(/<strong>(\d+)\.\s*([^<]+)<\/strong>/);
|
||||
if (t) topic = { order: Number(t[1]), name: TOPIC_ALIASES[t[2]!.trim()] ?? t[2]!.trim() };
|
||||
if (t) topic = { order: Number(t[1]), name: TOPIC_ALIASES[t[2]!.trim()] ?? t[2]!.trim(), phase };
|
||||
if (!topic) continue;
|
||||
const n = line.match(/<td align="center">(\d+)<\/td>/);
|
||||
if (n && !map.has(Number(n[1]))) map.set(Number(n[1]), topic);
|
||||
@@ -236,9 +262,43 @@ async function readmeTopics(): Promise<Map<number, Topic>> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Blume folder meta: exact topic label (the folder slug loses `/` and case),
|
||||
* curriculum order, and the group's sidebar icon. An unplanned category group
|
||||
* (warm-ups) has no README number and sorts at 0, ahead of topic 1, so the
|
||||
* Folder slug for a topic or phase name. Blume reads a leading `<digits>-` on a
|
||||
* folder as a sidebar-order prefix and strips it from the route (`1-d-…` →
|
||||
* `/d-…`), so a slug that would start that way keeps the digits glued to the
|
||||
* next token (`1d-dynamic-programming`).
|
||||
*/
|
||||
function slugify(name: string): string {
|
||||
return name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-|-$/g, "")
|
||||
.replace(/^(\d+)-/, "$1");
|
||||
}
|
||||
|
||||
/**
|
||||
* Content folder for a topic, relative to `DOCS`: `(0N-<phase>)/<topic>` for a
|
||||
* planned topic (the phase is a `(group)`, so the route is still `/<topic>`),
|
||||
* bare `<topic>` for an unplanned category group.
|
||||
*/
|
||||
function topicDir(topic: Topic): string {
|
||||
const slug = slugify(topic.name);
|
||||
return topic.phase ? `${phaseDir(topic.phase)}/${slug}` : slug;
|
||||
}
|
||||
|
||||
function phaseDir(phase: Phase): string {
|
||||
return `(${String(phase.order).padStart(2, "0")}-${slugify(phase.name)})`;
|
||||
}
|
||||
|
||||
/** Blume `(group)` meta for a phase: the overview page's heading, in phase order. */
|
||||
function phaseMeta(phase: Phase): string {
|
||||
return `import { defineMeta } from "blume";\n\nexport default defineMeta({ title: ${JSON.stringify(`Phase ${phase.order}: ${phase.name}`)}, order: ${phase.order} });\n`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blume folder meta for a topic: exact label (the folder slug loses `/` and
|
||||
* case), curriculum order, the sidebar icon, and `display: "group"` so the
|
||||
* topic collapses under its phase heading. An unplanned category group
|
||||
* (warm-ups) has no README number and sorts at 0, ahead of phase 1, so the
|
||||
* sidebar opens on the basics.
|
||||
*/
|
||||
function groupMeta(topic: Topic): string {
|
||||
@@ -246,6 +306,7 @@ function groupMeta(topic: Topic): string {
|
||||
if (!icon) console.warn(`no icon for group ${JSON.stringify(topic.name)}: add it to TOPIC_ICONS`);
|
||||
const fields = [`title: ${JSON.stringify(topic.name)}`, `order: ${topic.order ?? 0}`];
|
||||
if (icon) fields.push(`icon: ${JSON.stringify(icon)}`);
|
||||
fields.push(`display: "group"`);
|
||||
return `import { defineMeta } from "blume";\n\nexport default defineMeta({ ${fields.join(", ")} });\n`;
|
||||
}
|
||||
|
||||
@@ -427,6 +488,11 @@ for await (const rel of new Bun.Glob("**/*.{js,py}").scan(WORK)) {
|
||||
}
|
||||
|
||||
const topics = await readmeTopics();
|
||||
// An unplanned problem whose work/ category is also a README topic name (a
|
||||
// `Hash Table` warm-up) files under that topic, in its phase, not a second
|
||||
// root-level `hash-table/`.
|
||||
const topicByName = new Map<string, Topic>();
|
||||
for (const topic of topics.values()) topicByName.set(topic.name, topic);
|
||||
|
||||
/** Insert a number-free `sidebar.label` into existing frontmatter when missing. */
|
||||
function ensureLabel(page: string, h: Header): string {
|
||||
@@ -464,29 +530,23 @@ for (const rel of (await Array.fromAsync(new Bun.Glob("**/*.mdx").scan(DOCS))).s
|
||||
|
||||
const report: [string, string, string][] = [];
|
||||
const ordered = [...solutions.values()].sort((a, b) => a.num - b.num);
|
||||
const groups = new Map<string, Topic>(); // folder -> topic, for meta.ts
|
||||
const groups = new Map<string, Topic>(); // topic folder -> topic, for meta.ts
|
||||
const phases = new Map<string, Phase>(); // phase folder -> phase, for meta.ts
|
||||
const vacated = new Set<string>(); // folders a page moved out of; removed below if empty
|
||||
|
||||
for (const sol of ordered) {
|
||||
const langs = Object.keys(sol.code).sort().join("+");
|
||||
const workRef = `${sol.num}.${sol.slug} (${langs})`;
|
||||
// <topic>/ folder (a real route segment, so its index.mdx is the topic landing
|
||||
// page) + leetcode-number prefix: numeric sidebar order, prefix stripped from the URL.
|
||||
// An unplanned problem's category may share a folder with a numbered topic
|
||||
// (`Hash Table` warm-ups under topic 1); the numbered one owns the meta.
|
||||
const topic = topics.get(sol.num) ?? { name: sol.category };
|
||||
// Blume reads a leading `<digits>-` on a folder as a sidebar-order prefix and
|
||||
// strips it from the route (`1-d-…` → `/d-…`), so a slug that would start that
|
||||
// way keeps the digits glued to the next token (`1d-dynamic-programming`).
|
||||
const group = topic.name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-|-$/g, "")
|
||||
.replace(/^(\d+)-/, "$1");
|
||||
if (groups.get(group)?.order === undefined) groups.set(group, topic);
|
||||
const name = `${group}/${sol.num}-${sol.slug}.mdx`;
|
||||
// (0N-<phase>)/<topic>/ folder (the topic is a real route segment, so its
|
||||
// index.mdx is the landing page) + leetcode-number prefix: numeric sidebar
|
||||
// order, prefix stripped from the URL.
|
||||
const topic = topics.get(sol.num) ?? topicByName.get(sol.category) ?? { name: sol.category };
|
||||
const dir = topicDir(topic);
|
||||
groups.set(dir, topic);
|
||||
if (topic.phase) phases.set(phaseDir(topic.phase), topic.phase);
|
||||
const name = `${dir}/${sol.num}-${sol.slug}.mdx`;
|
||||
const existing = pages.get(sol.num);
|
||||
await mkdir(join(DOCS, group), { recursive: true });
|
||||
await mkdir(join(DOCS, dir), { recursive: true });
|
||||
|
||||
if (existing) {
|
||||
const page = await Bun.file(join(DOCS, existing)).text();
|
||||
@@ -515,24 +575,37 @@ for (const sol of ordered) {
|
||||
}
|
||||
}
|
||||
|
||||
// Script-owned folder meta: one per live group, rewritten only when it differs.
|
||||
for (const [group, topic] of groups) {
|
||||
const path = join(DOCS, group, "meta.ts");
|
||||
const meta = groupMeta(topic);
|
||||
// Script-owned folder metas — one per live phase and topic folder — rewritten
|
||||
// only when they differ.
|
||||
const metas: [label: string, dir: string, meta: string][] = [
|
||||
...[...phases].map(([dir, phase]): [string, string, string] => [`phase ${phase.order}`, dir, phaseMeta(phase)]),
|
||||
...[...groups].map(([dir, topic]): [string, string, string] => [`topic ${topic.order ?? "-"}`, dir, groupMeta(topic)]),
|
||||
];
|
||||
for (const [label, dir, meta] of metas) {
|
||||
const path = join(DOCS, dir, "meta.ts");
|
||||
if ((await Bun.file(path).exists()) && (await Bun.file(path).text()) === meta) continue;
|
||||
await Bun.write(path, meta);
|
||||
report.push([`topic ${topic.order ?? "-"}`, `${group}/meta.ts`, "written"]);
|
||||
report.push([label, `${dir}/meta.ts`, "written"]);
|
||||
}
|
||||
|
||||
// A group every page left behind is dead: drop its meta and the folder itself.
|
||||
for (const dir of vacated) {
|
||||
if (groups.has(dir)) continue;
|
||||
const left = await readdir(join(DOCS, dir));
|
||||
if (left.some((f) => f !== "meta.ts")) continue;
|
||||
// A folder every page left behind is dead: drop its meta and the folder itself,
|
||||
// then the phase folder above it if that emptied too. A folder that still holds
|
||||
// anything else (a hand-written index.mdx, another topic) stops the climb.
|
||||
for (const start of vacated) {
|
||||
for (let dir = start; dir !== "."; dir = dirname(dir)) {
|
||||
if (groups.has(dir) || phases.has(dir)) break;
|
||||
let left: string[];
|
||||
try {
|
||||
left = await readdir(join(DOCS, dir));
|
||||
} catch {
|
||||
break; // already removed via a sibling's climb
|
||||
}
|
||||
if (left.some((f) => f !== "meta.ts")) break;
|
||||
if (left.length) await unlink(join(DOCS, dir, "meta.ts"));
|
||||
await rmdir(join(DOCS, dir));
|
||||
report.push(["", dir, "removed (empty)"]);
|
||||
}
|
||||
}
|
||||
|
||||
const w0 = Math.max(...report.map((r) => r[0].length), 9);
|
||||
const w1 = Math.max(...report.map((r) => r[1].length), 9);
|
||||
|
||||
@@ -7,7 +7,13 @@ export default defineConfig({
|
||||
site: "https://prdlk.github.io",
|
||||
base: "/leetcode",
|
||||
},
|
||||
lastModified: "git",
|
||||
content: {
|
||||
root: "content",
|
||||
},
|
||||
navigation: {
|
||||
sidebar: {
|
||||
display: "flat", // "flat" | "group" | "page"
|
||||
},
|
||||
},
|
||||
});
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Binary Search", order: 5, icon: "search" });
|
||||
export default defineMeta({ title: "Binary Search", order: 5, icon: "search", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Hash Table", order: 1, icon: "hash" });
|
||||
export default defineMeta({ title: "Hash Table", order: 1, icon: "hash", display: "group" });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Phase 1: Linear Structures", order: 1 });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Monotonic Stack", order: 7, icon: "trending-up" });
|
||||
export default defineMeta({ title: "Monotonic Stack", order: 7, icon: "trending-up", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Prefix Sum", order: 2, icon: "sigma" });
|
||||
export default defineMeta({ title: "Prefix Sum", order: 2, icon: "sigma", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+3
-3
@@ -55,7 +55,7 @@ Without an invariant, shrinking the window becomes arbitrary. You no longer know
|
||||
The window size never changes. The main task is updating the window state efficiently when one element enters and one leaves.
|
||||
:::
|
||||
|
||||

|
||||

|
||||
|
||||
### 2. Flexible-size windows with a validity rule
|
||||
|
||||
@@ -63,7 +63,7 @@ The window size never changes. The main task is updating the window state effici
|
||||
Here the window expands until invalid, then shrinks until valid again.
|
||||
:::
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
### 3. Frequency-tracking windows
|
||||
@@ -72,7 +72,7 @@ Here the window expands until invalid, then shrinks until valid again.
|
||||
The difficulty comes from keeping the bookkeeping correct as characters enter and leave.
|
||||
:::
|
||||
|
||||

|
||||

|
||||
|
||||
## How Sliding Window Differs From Other Two-Pointer Families
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Sliding Window", order: 4, icon: "app-window" });
|
||||
export default defineMeta({ title: "Sliding Window", order: 4, icon: "app-window", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Stack", order: 6, icon: "layers" });
|
||||
export default defineMeta({ title: "Stack", order: 6, icon: "layers", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Two Pointers", order: 3, icon: "arrow-left-right" });
|
||||
export default defineMeta({ title: "Two Pointers", order: 3, icon: "arrow-left-right", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Hybrid Structures", order: 9, icon: "combine" });
|
||||
export default defineMeta({ title: "Hybrid Structures", order: 9, icon: "combine", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Linked List", order: 8, icon: "link" });
|
||||
export default defineMeta({ title: "Linked List", order: 8, icon: "link", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Matrix Index Math", order: 10, icon: "grid-3x3" });
|
||||
export default defineMeta({ title: "Matrix Index Math", order: 10, icon: "grid-3x3", display: "group" });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Phase 2: Nodal & Grid", order: 2 });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Binary Search Tree", order: 13, icon: "git-fork" });
|
||||
export default defineMeta({ title: "Binary Search Tree", order: 13, icon: "git-fork", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Heap / Priority Queue", order: 14, icon: "triangle" });
|
||||
export default defineMeta({ title: "Heap / Priority Queue", order: 14, icon: "triangle", display: "group" });
|
||||
@@ -0,0 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Phase 3: Hierarchical", order: 3 });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Tree BFS", order: 12, icon: "network" });
|
||||
export default defineMeta({ title: "Tree BFS", order: 12, icon: "network", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Tree DFS", order: 11, icon: "folder-tree" });
|
||||
export default defineMeta({ title: "Tree DFS", order: 11, icon: "folder-tree", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Trie", order: 15, icon: "spell-check" });
|
||||
export default defineMeta({ title: "Trie", order: 15, icon: "spell-check", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Graph BFS", order: 17, icon: "radar" });
|
||||
export default defineMeta({ title: "Graph BFS", order: 17, icon: "radar", display: "group" });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
import { defineMeta } from "blume";
|
||||
|
||||
export default defineMeta({ title: "Graph DFS", order: 16, icon: "waypoints" });
|
||||
export default defineMeta({ title: "Graph DFS", order: 16, icon: "waypoints", display: "group" });
|
||||
Loaded 100 of 138 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user