diff --git a/.claude/skills/problem-approach/SKILL.md b/.claude/skills/problem-approach/SKILL.md new file mode 100644 index 0000000..b2ced73 --- /dev/null +++ b/.claude/skills/problem-approach/SKILL.md @@ -0,0 +1,150 @@ +--- +name: problem-approach +description: Write the `## Approach` section — a Mermaid flowchart that traces the submitted solution — for every docs solution page under apps/docs/content/ that lacks one, using the repo's exact placement and node conventions. Use when asked to add/implement/fill in missing approaches, draw the approach diagram for a problem page, or when `/problem-approach` is run. +--- + +# Problem approach diagrams + +Every solution page (`apps/docs/content/()/-.mdx`) has three +hand-owned sections around the script-owned one: + +``` +frontmatter → → ::::warning (maybe) → ### Example N / ### Constraints +## Approach ← this skill (Mermaid flowchart of the code below) +## Solution ← bun run sync owns this; never edit inside it +## Explanation ← bun run videos --write (NeetCode embed); not this skill +``` + +`sync.ts` regenerates only `## Solution`, so an `## Approach` placed **before** it +survives every re-sync; anything placed inside `## Solution` is overwritten on the +next `work/` push. + +## The command: fill every missing approach + +1. **Find the pages** (numbered pages with no `## Approach` heading): + + ```sh + grep -L '^## Approach' apps/docs/content/*/*.mdx + ``` + +2. **For each page**, read `## Solution` and write the diagram from *that code* — the + one on the page, not the textbook algorithm. The reader compares diagram and code + line by line; the diagram is a trace, not a lecture. + +3. **Insert** the section between the `### Constraints:` list and `## Solution`, + blank-line separated on both sides: + + ````md + - `-100 <= Node.val <= 100` + + ## Approach + + ```mermaid + flowchart TD + … + ``` + + ## Solution + ```` + +4. **Check** each diagram by hand against the syntax rules below (the docs build does + not parse Mermaid — a broken diagram fails only in the browser), then run the + docs build once at the end and review the pages in `bun run dev`: + + ```sh + cd apps/docs && bunx blume build --isolated && rm -rf .blume-verify + ``` + +Pages with two languages (``) get **one** diagram, traced from the +Python version. Pages with only JavaScript trace the JavaScript. + +## Diagram conventions + +Reference page: `apps/docs/content/(array)/15-3sum.mdx`. Every existing diagram +follows this shape: + +```mermaid +flowchart TD + S(["threeSum(nums)"]) --> O["nums.sort() — duplicates become adjacent"] + O --> F{"more i in 0..n-1?"} + F -- no --> E(["return result"]) + F -- yes --> D{"nums[i] == nums[i-1]?"} + D -- yes --> F + D -- no --> P["left = i+1, right = n-1, target = -nums[i]"] + P --> W{"left < right?"} + W -- no --> F + W -- yes --> C["current = nums[left] + nums[right]"] + C --> Q{"current vs target"} + Q -- equal --> A["append triplet, skip equal neighbours, left += 1, right -= 1"] + A --> W + Q -- "current < target" --> L["left += 1 — need a bigger sum"] + L --> W + Q -- "current > target" --> R["right -= 1 — need a smaller sum"] + R --> W +``` + +- `flowchart TD`, two-space indent, one edge per line, edges listed in execution + order (entry first, exits as soon as they are reachable). +- **Entry** is a stadium holding the signature: `S(["threeSum(nums)"])`. **Every + exit** is a stadium: `E(["return result"])`, `R(["return true"])`. +- **Statements** are rectangles `["…"]`, in the code's own identifiers and operators + (`left += 1`, `freq[n] = (freq[n] or 0) + 1`). Several trivial assignments may share + one node, comma-separated. +- **Decisions** are diamonds `{"…?"}` with `-- yes -->` / `-- no -->` edges. A + three-way branch names the outcomes: `-- equal -->`, `-- "current < target" -->` + (quote an edge label whenever it holds `<`, `>`, or spaces around operators). +- **Loops** are a decision: `for` → `{"more n in nums?"}`, `while` → the condition + verbatim `{"left < right?"}`. `-- no -->` goes to whatever follows the loop; the + body's last node edges back to the decision. `continue` is an edge back to the loop + decision (`D -- yes --> F` above); `break` is an edge to the node after the loop. +- **Recursion** is a statement, not an expanded subgraph: `A["left = invertTree(root.left)"]`. + The base case is the first decision after entry. +- **Classes** (design problems) use one `subgraph name["method(args)"]` per public + method, plus a `state["…"]` subgraph describing the fields, with `state --> method` + edges — see `(hash-table)/146-lru-cache.mdx`. Private helpers are named inside the + method nodes (`"_remove_node then _add_node — move it beside the tail"`), not drawn. +- **Annotate the why with an em dash** inside the node, sparingly (one clause, a few + per diagram): `"nums.sort() — duplicates become adjacent"`, `"map = {0: 1} — the + empty prefix"`. The dash explains the invariant that makes the step correct — the + one thing the code does not say. +- **Node ids**: one or two capitals, unique per diagram (`S I L Q C E R W A B`). Class + diagrams prefix per method (`G1`, `P1`). + +### Syntax rules (a diagram that breaks the page is worse than none) + +- Wrap **every** label in double quotes — brackets, parentheses, `<`, `>` and `|` in an + unquoted label break the parser. +- Never put `"` inside a label; use `'` for string literals (`"s == ''?"`). +- Never use `|` anywhere — not in node labels, not as `-->|text|` edge syntax; edge + labels are always `-- text -->`. Write `or` for a logical or. +- Every id an edge references must be declared with a shape the first time it appears. +- Balanced: each `subgraph` has an `end`; each fence opens ```` ```mermaid ```` and closes ```` ``` ````. + +### Code that does not run + +Trace it anyway — the diagram documents what was submitted — and put a `::::warning` +callout **before** the fence naming exactly why it fails (`(array)/121-best-time-to-buy-and-sell-stock.mdx`): + +````md +## Approach + +::::warning +The diagram traces the code below literally. That code does not run: `curr` and `ans` are never initialised, so the first `curr > left` test raises `NameError`. +:::: + +```mermaid +… +``` +```` + +Do not fix the code on the page: `## Solution` mirrors `work/1`, and the fix belongs +there (then `bun run sync`). + +## Do not + +- Do not write prose approaches, complexity tables or alternative algorithms — the + section is one flowchart (plus the warning callout when the code is broken). +- Do not touch `## Solution` or anything after it; `## Explanation` is filled by + `bun run videos --write`. +- Do not add an approach to `reference/` pages or `index.mdx` — only numbered + solution pages (`title: 'NN. …'`) carry one.