中文

LeetCode Frequency 888 Spec

This book is a compact practice surface for LeetCode China interview preparation.

Typography and Math Contract

This book inherits the repository-wide book style contract in BOOK_STYLE.md: all prose, headings, controls, tables, captions, and ordinary UI text must default to PingFang. Code blocks, inline code, terminal snippets, and code editors use the Cursor/LeetCode stack Monaco, "Cascadia Code", Consolas, "Courier New", ui-monospace, SFMono-Regular, Menlo, monospace. Problem constraints, variables, arrays, matrices, complexity, numeric bounds, and benchmark-style metrics should use LaTeX/KaTeX whenever possible.

Data Contract

The target ranking starts from the LeetCode China problemset sorted by 出题频率 on May 16, 2026. The pinned daily-question row is excluded because it is not part of the frequency order. The source ranking target is Top 888.

The default problem list is deduplicated. Obvious duplicates are detected by a normalized Chinese title, such as the LCCI/LCR variant of the same canonical problem. The row with the higher frequency rank is kept, and the removed row is recorded in the duplicate audit section so it can be checked manually. The top rank shown on kept rows remains the original frequency rank, so removed rows leave intentional gaps.

Hot 100 membership comes from the public Hot 100 study plan. If a Hot 100 problem is outside the Top 888, it is appended without a Top 888 rank and keeps its frequency-order position for Hot 100 sorting.

ByteDance membership comes from the LeetCode China company favorite lists: bytedance-all, bytedance-thirty-days, bytedance-three-months, bytedance-six-months, and bytedance-more-than-six-months. The page mirrors those five filters: all ByteDance, past 30 days, past 3 months, past 6 months, and more than 6 months ago. The intended full ByteDance source has 1,503 rows and is sorted by company frequency. Rows not already present in the Top 888 or Hot 100 supplement are appended after those rows and keep their ByteDance rank.

ByteDance company data is generated by npm run sync:leetcode-bytedance. LeetCode China gates company favorites behind the logged-in Plus session, so the reproducible full sync accepts LEETCODE_CN_COOKIE. The script uses the same favoriteQuestionList GraphQL operation that the company page uses, paginates by skip and limit, and sorts with { sortField: "FREQUENCY", sortOrder: "DESCENDING" }. If no authenticated rows are available, it writes a clearly marked legacy Top 888 fallback. The script can also merge Top 100 bucket rows exported from the Chrome-rendered logged-in company pages. Those rows are marked as official page Top100 and override the corresponding all, past 30 days, past 3 months, past 6 months, or older-than-6 months rank; legacy rows remain marked as old data. The page must expose the source of each bucket instead of pretending the 1,503-row company list is complete.

LingShen membership comes from the 12 topic links in 灵茶山艾府’s “How to practice scientifically” post: sliding window and two pointers, binary search, monotonic stack, grid graphs, bit manipulation, graph algorithms, dynamic programming, data structures, math, greedy/thinking, linked list/trees/ backtracking, and strings. The sync command is npm run sync:leetcode-lingshen. It reads the original problem order, topic grouping, rating, and paid-only hint from the LeetCode China discussion posts, then fills title, tags, statement preview, approach preview, and generic study checks from LeetCode metadata and local public Doocs material. LingShen problems not already present in Top 888, ByteDance, or series supplements are appended as LingShen supplemental rows and still participate in search, local state, opened practice panels, list flow, and suggested flow.

Contest difficulty ratings are generated by npm run sync:leetcode-contest-ratings from the public zerotrac/leetcode_problem_rating dataset. The page merges those ratings into the whole book rather than showing them only inside LingShen lists: the main table has a dedicated rating column, and tag popovers, related-problem cards, series/category member lists, and search indexes must all carry the same rating fields. Problems with contest-source data keep the contest name, problem index, and source label. Problems missing a zerotrac row may fall back to a LingShen rating when available, with the fallback source preserved internally. Problems with no rating source render --; the page must not fabricate estimated ratings.

Official code templates are generated by a local sync script rather than by cross-origin LeetCode requests from the GitHub Pages runtime. The command is npm run sync:leetcode-templates. It prefers LeetCode China’s public GraphQL question.codeSnippets field, then falls back to the matching official LeetCode global template when the China endpoint is rate-limited or returns a challenge page. The script can use LEETCODE_CN_COOKIE or LEETCODE_COOKIE for an authenticated session and supports --missing-only so later runs merge existing results and fetch only missing problems. The sync target is the deduplicated book catalog, including ByteDance-only supplemental rows, so supplements get the same official editor defaults as Top 888 rows. Results are written to src/data/leetcode-code-templates.ts, and the page reads only that static module.

ByteDance-only supplemental rows must not render generic placeholder study text. If a ByteDance row is not already in the main problem dataset, src/data/leetcode-bytedance.ts carries its local statement preview, topic tags, approach preview, and generic study checks. Those fields come from the public LeetCode problem content plus local study synthesis, while examples remain omitted from the rendered local statement.

Official data ranges are generated by npm run sync:leetcode-constraints. The script reads the same merged book rows that the page renders, extracts the 提示 / Constraints list from LeetCode China’s public problem statement, and falls back to the matching public Doocs statement for paid-only questions when the LeetCode API omits the content. Results are written to src/data/leetcode-problem-constraints.ts. Every rendered problem row must have nonempty data ranges. The local practice panel appends those ranges as one compact inline constraints sentence at the end of the statement body, not as a separate bordered block or bullet list. Because these constraints are mostly mathematical expressions, inline constraint separators use spaced ASCII semicolons in every locale; Chinese prose labels keep Chinese punctuation where it reads naturally. Each constraint item’s own trailing period or semicolon is trimmed before inline joining, so the rendered sentence never produces broken punctuation such as 。 ;. Constraint text must use the same readable weight and color as the statement body, not faint muted helper text. The statement and constraint sentence use the same larger PingFang-first reading font and normal visual weight. Questions whose official statement does not separate data ranges, such as some database tasks, receive an explicit note to use the table schema or input definition in the statement.

Statement and data-range math is generated by npm run sync:leetcode-math. The script reads the same merged book rows, normalizes common LeetCode math fragments, and writes KaTeX-rendered static HTML to src/data/leetcode-problem-math.ts. Superscripts, subscripts, matrix or grid dimensions, Big-O notation, numeric ranges, and comparison chains must render as math instead of broken plain text such as n 2, m x n, or 10 9. Obvious statement variables and programming identifiers such as n, height, height[i], haystack, and needle should also render as inline math when that improves readability; ordinary prose numbers stay as text unless they are part of a formula or range. The page reads only the generated escaped HTML and imports KaTeX CSS globally. Generated statement HTML and title hover previews omit official example sections; examples remain data for the official run-examples workflow, not prose inside the local statement. If an older statementPreview is a truncated preview string, the generator must use a local official-statement override so the rendered page never shows half sentences, dangling parentheses, or flattened lists. npm run check:leetcode-math must pass before publishing math or statement changes.

Official statement visuals are generated by npm run sync:leetcode-statement-assets. The script reads the same merged book rows, fetches LeetCode China’s official statement HTML, and stores sanitized static snippets in src/data/leetcode-problem-assets.ts. The page renders official images from the statement and schema-style tables that appear before the example or constraints sections inside the opened practice statement panel. Title hover previews remain text-only, and the page does not make LeetCode API requests for statement-asset metadata at runtime.

Official related problems are also generated by a local sync script. The command is npm run sync:leetcode-related. It reads LeetCode China’s public GraphQL question.similarQuestions field for every Top 888, Hot 100, and ByteDance supplemental row, then writes the static result to src/data/leetcode-related.ts. The page does not make related-problem requests at runtime. At build time it combines the official list with same-series detection from local slugs, such as house-robber, house-robber-ii, and house-robber-iii, plus a small same-track set derived from shared topic tags and frequency rank.

Previously verified exact frequency percentages are preserved. New rows that can be ordered by frequency but do not expose an exact percentage in the public response are labeled with or with their supplemental source, so exact and estimated percentages are not confused.

Company follow-ups are separate from generated study checks. A company follow-up is included only when a public LeetCode Discuss interview post mentions the company, the problem or a close variant, and the follow-up prompt. Each included follow-up stores a concise answer, the company name, and the source link. If no public source was found for a problem, the page says so rather than assigning a company by inference.

Problem study content must explain the individual problem first, not merely combine tag-level templates. approachPreview needs to name the problem’s own state, invariant, boundaries, and correctness reason; when the key idea is a compression from a simpler solution to the optimal one, such as dynamic programming compressed into greedy boundaries, that compression must be stated. followUps must be concrete variants or pitfalls that naturally belong to the problem, with short answers usable in an interview. implementationReferences must include at least one submit-ready primary solution; for high-frequency problems that are easy to misunderstand, add a baseline solution, path reconstruction, unreachable-case handling, or another reference that explains the tradeoff behind the primary solution. Generic prompts such as boundary cases, complexity, or space compression may supplement the entry, but they must not replace problem-specific content.

Page Contract

The page does not show the global site header. The title area uses a compact workspace layout, and the large cover is not shown in the first viewport. Stats and secondary metadata live below the working list. The problem list is the primary workspace; on desktop, the first problem rows should be visible without scrolling. The table is sized to fit the content column without an internal horizontal scrollbar.

Each row shows the identifiers that matter for practice:

  1. the Top 888 frequency rank;
  2. the Hot 100 rank, sorted by frequency rather than by the study-plan order;
  3. the ByteDance company rank when the row is in the ByteDance company list;
  4. the original LeetCode frontend problem id inside the clickable title.

Approach, implementation, tags, and related controls are attached to the title cell so the pointer does not need to cross the table. Clicking the linked title still opens LeetCode directly, but hover/focus on that title must show the same warm yellow block popover used by the other previews, containing the local statement and compact data ranges. The statement is also shown inside the practice panel above the editor. Moving slightly right to Approach shows the approach. Moving slightly farther right to Implementation shows the reference implementation. Moving one more small step to Tags shows topic tags and supplemental badges. The Related preview shows same-series problems first, then official LeetCode related problems, then a compact same-track high frequency set. In-book related problems open directly in the local practice panel; the same-series section also offers a compact action that starts list flow for that series. Related problems outside the book open on LeetCode China and keep their paid-only marker when LeetCode reports one. These preview targets stay compact and must not increase the normal row height.

Hover details for the title, approach, implementation, tags, related problems, suggested practice, shortcut help, and daily stats must use the page’s own warm yellow block popovers. The page must not depend on browser-native title tooltips or custom gray strip pseudo-tooltips. Text that used to live in a gray strip, such as “hover to view; click or Enter/Space to pin”, belongs at the top of the matching yellow popover. Plain controls without a yellow popover keep only accessible aria-label text and the central shortcut list. As an acceptance check, the rendered practice page DOM should not leave any title attributes that would trigger browser-native gray tooltips.

All page-owned hover popovers must be hover-trackable by default. Even when there is visual spacing between the trigger and the floating panel, a transparent hit-testable bridge or an equivalent delayed-close mechanism must connect them so moving the pointer downward or upward from the trigger into the panel does not make the popover disappear. The open hover hit area includes the trigger, the bridge, and the popover body; the popover may close only after the pointer leaves all three. This applies to title, approach, implementation, tags, related problems, category or series “Ideas”, suggested practice, shortcut help, daily stats, achievements, and every future hover detail. Interactive or scrollable popovers must not use pointer-events: none in a way that makes the panel close as soon as the pointer enters it. If a popover flips above the trigger because there is not enough space below, the bridge must flip above the trigger as well. Acceptance: with a normal mouse path from the trigger center to the first line, scrollable area, or internal button of the popover, the popover must remain visible without flicker, closing, or requiring the user to pin it with a click first.

The duplicate audit appears below the working list in a collapsed details section. It lists every removed duplicate, the kept row, and the original frequency ranks without taking space before the first visible rows. Long secondary explanations, including the suggested-practice ranking guide and the Chrome extension install guide, sit in the same collapsed stack immediately below the duplicate audit. Keeping these collapsible sections together preserves an orderly, tidy, and visually clean page instead of scattering long help blocks around stats and settings.

The page supports 10, 20, 50, 100, and custom page sizes. It defaults to 20 items per page. Pagination controls appear both above and below the problem table, with first page, previous page, next page, last page, and a page number jump input. Left and right arrow keys turn pages when the current focus is not inside search, filters, selectors, the practice editor, or another editable control.

The top of the page is intentionally compact. A single-line title/action row stays at the page opening for orientation, while summary and stats move below the working list. Search, filters, pagination, and the problem rows remain the first visual priority and should appear without excessive scrolling.

Filters are grouped by scope, ByteDance, and practice state. Scope includes all problems, Hot 100, and sourced company follow-ups. ByteDance includes all, past 30 days, past 3 months, past 6 months, and more than 6 months ago. State includes unsolved, needs thought, and not mastered. Text search is centered on the problem itself: id, Chinese title, and English slug are weighted highest; series names, LingShen topic names, and tags are secondary; Hot 100, ByteDance, and LingShen collection markers are only low-weight helpers. Search results are ordered by relevance first, then by the active filter’s normal order as a tie-breaker. Study-check answers, company follow-ups, implementation sources, and related-problem text no longer pull unrelated high-frequency rows ahead of title matches. Matching supports basic fuzziness: case and full-width normalization, space/hyphen equivalence, all-token matches, prefix/substring matches, and short ordered-character matches.

Clicking a row opens a local practice panel. The panel stores drafts only in the current browser’s local storage and provides language selection, official code-template initialization, editing, copy, reset, direct LeetCode link, and optional extension submit. Code drafts roll on Beijing calendar days: the first page load in a browser only stamps the current day, and later day changes clear all code drafts so each day starts from official templates or local fallbacks again. This rollover affects only code drafts; it does not clear solved status, visited links, per-problem PBs, or daily timing history. The footer exposes an auto-reset switch for this Beijing-midnight rollover; it is on by default and can be turned off per browser. The language selector comes from the official codeSnippets synced into the repository. If a problem is still missing an official template, the page uses a local fallback template and says so. The practice editor uses a native textarea over a local syntax-highlight layer covering the common languages in the official templates, avoiding a heavier editor dependency. The native editor still needs LeetCode-like editing basics: Enter keeps the current line indentation and adds one indentation level after opening braces, brackets, parentheses, or Python colons; Tab and Shift+Tab indent and outdent the current line or selected lines; typing a closing brace, bracket, or parenthesis on an indentation-only line aligns it back one level. Plain Backspace in leading indentation deletes back to the previous 4-space tab stop, so an 8-space indent becomes 4 spaces, a 6-space indent becomes 4 spaces, and a partial indent before the first tab stop clears to the line start. The editor shows a fixed line-number gutter synchronized with the textarea and highlight layer. The editor defaults to an auto-growing height equal to the current code line count plus one spare line, growing with the code up to a bounded maximum so short templates do not leave a large blank editor area. A compact toolbar toggle can switch the editor to a 14-visible-line fixed-height mode when the user wants a stable panel size; fixed-height mode remains resizable and scrollable. While the auto-growing editor is being typed near the bottom of the viewport, the page reveals the current caret line and keeps it in a comfortable writing zone instead of making the user manually chase the page. When a default template is first opened, reset, or selected by language change, focus lands inside the function body where the user is expected to start writing. The practice-page UI, including statement text, popovers, timing metrics, keyboard hints, and reward overlays, defaults to a PingFang-first text stack with Apple and common system sans fallbacks. This page font is not user-configurable and does not change the code editor font. Editor appearance controls live in the footer: theme, font, font size, and line spacing. The default light theme uses the same background as the page while keeping Cursor Light+ token colors, and the default editor font mirrors the current Cursor font stack (Monaco, 'Cascadia Code', Consolas, 'Courier New', monospace). The default size and line spacing use a tighter practice density to reduce vertical space for short templates. Alternate editor themes, monospace stacks, font sizes, and line spacings remain selectable per browser. Reloading the page restores the previous practice view from local storage: current filters, search text, page size, page number, expanded problem, page scroll position, editor selection, and editor internal scroll position. If synced problem data changes and a saved problem is no longer visible under the saved filters, the page falls back to the matching filtered list without opening an editor. Direct practice links override that saved view. A URL with ?problem=<slug> or ?id=<frontendId> clears local search and filters, jumps to the matching problem’s page, opens its practice panel, and focuses the local editor. The link never resets or replaces an existing local draft; it only chooses which problem to open. If the URL target is unknown, the page keeps the saved local view. Each problem row exposes a compact curved-arrow share action beside the preview controls. It copies a randomized invitation message plus the current-language problem=<titleSlug> URL, then shows the full copied text in a temporary notice anchored near the share action. The notice disappears after a short delay or on the next page click, so the pasted text can invite another person to open the same problem directly. The Chinese invitation pool uses handwritten, playful friend-to-friend copy across several tones such as asking for help, teasing, pretending to be stuck, inviting a shared solve, and asking for an AC demo. The picker avoids reusing the most recent tones so repeated shares feel less repetitive. When a practice editor is open, the cleaned local problem statement is rendered as normal page UI directly above the code editor. It is on by default, uses a moderate reading size rather than code comments, and can be collapsed or shown again from the statement panel; that visibility choice is saved per browser. Opening a problem or moving between problems with keyboard navigation frames the problem title row, statement, and editor together below the sticky header, so the editor keeps focus without hiding the title or local statement above it. Editor shortcuts match the primary LeetCode muscle memory: Cmd+' runs the official example testcases and Cmd+Enter performs a full LeetCode submit. Inside the editor, Cmd+/ toggles line comments for the current language while preserving the active selection or caret. Cmd+Left and Cmd+Shift+Left move or select to the first non-whitespace code character before falling back to the true line start, matching the LeetCode editor’s indent-aware line-start behavior. Practice navigation is also keyboard-first: Option+J or Option+Down opens and focuses the next visible problem’s editor, while Option+K or Option+Up opens and focuses the previous one. Default-on local route toggles on the timing board let these keyboard route jumps ignore database-tagged SQL problems and pure frontend problems whose templates are only JavaScript/TypeScript, without hiding those problems from the list. Common page actions must also be keyboard reachable: / focuses search, Option+1 through Option+3 switch scope filters, Option+4 through Option+8 switch ByteDance filters, Option+9, Option+0, and Option+- switch state filters, Option+P focuses page jump, and Option+Left / Option+Right jump to first / last page. The current problem toolbar supports Cmd+Option+L for language focus, Cmd+Option+C for copy, Cmd+Option+H for editor height, Cmd+Option+R for current draft reset, and Cmd+Option+D/S/M for done/review/mastered state. Timing shortcuts include Cmd+Option+T for current-problem restart, Cmd+Option+Shift+S for session restart, and Cmd+Option+Shift+T for clearing the current problem PB and last Accepted record. Compact shortcut affordances near pagination list every supported key without adding another tall block at the page end. All hover popovers must remain open while the pointer moves naturally from the trigger into the floating content, and close only after the pointer leaves that content.

Practice timing is automatic. Daily history stays collapsed into a hover/focus popover so it does not push the first problem rows down. Opening or keyboard-switching into a problem starts that problem’s forward timer without requiring a start button. The current-problem timer and session timer count only foreground practice time: they pause when the document is hidden or the browser window loses focus, then resume from the accumulated value when the page is visible and focused again. There is no idle timeout, because reading, debugging, and thinking without keyboard input are still valid practice time. A full LeetCode submit that returns Accepted records the elapsed foreground time from the latest switch/open moment, marks the problem done, updates the problem’s last Accepted time and personal best, and then resets the active-attempt timer for any repeat attempt. Running examples does not count as an Accepted solve. The page also starts a session timer when it loads and shows current problem time, session elapsed time, distinct session Accepted count, session average, today versus best daily count, current streak, seven-day count, and the current problem PB. The Today/Best metric must render as a compact slash value without spaces, such as 38/42, and must never truncate with an ellipsis or overlap adjacent metric cards at desktop, tablet, or 320 px mobile widths. The timing board should reflow to fewer metric columns before individual metric cards become too narrow for their values. The visible metric label provides the meaning, while assistive text expands the same value as today’s solved count and the best daily record. Day boundaries are always computed in Asia/Shanghai (北京时间), not the browser’s current local timezone. Session counters live only in memory for the current page load; per-problem PB/last Accepted and daily Accepted summaries persist in the browser practice store. Daily summaries store the unique solved problems, total Accepted submissions, total Accepted time, fastest single problem, first Accepted time, and last Accepted time for each Beijing date. The compact board surfaces comparison cues such as new daily record, tied daily record, best per-problem solve, fastest daily average, seven-day activity, and streak status. A collapsed daily-history view shows the last 14 Beijing calendar days for quick comparison. Manual reset controls may restart the current session timer or restart only the current active problem timer. A less prominent, confirmed control clears the active problem’s stored PB and last Accepted record without rolling back daily summaries. The normal flow remains automatic. Immersive practice flow is a default-off local toggle available from the timing board button or Cmd+Option+F; when it is enabled, only a full LeetCode submit that returns Accepted opens the next problem in the current filter and search order. If route skipping is enabled for SQL or pure frontend problems, list flow chooses the next problem in that same order that does not match the enabled skip category. This automatic transition uses the same problem-title, statement, and editor framing as a manual open, and editor focus must not immediately scroll that title or statement out of view. Passing sample runs never trigger this navigation.

Durable practice facts are stored as an append-only IndexedDB event log, not as whole-object localStorage writes. The event log is scoped to the browser origin and records full submit attempts, sample-run attempts, Accepted timing, manual done/review/mastered state changes, and current-problem timing clears. Opening the page migrates the previous localStorage progress, timing, and submission-stat JSON into stable legacy snapshot events exactly once, then rebuilds the visible projection from the event log. localStorage remains only as a compatibility cache for those projections and as storage for inherently tab-local or last-write-wins state such as editor drafts, scroll position, current page view, route toggles, and visited-link styling.

Multiple tabs must therefore append independent facts instead of rewriting the same JSON blob. After a tab appends an event it broadcasts a lightweight update with BroadcastChannel and also touches a storage pulse key as a fallback. Other open tabs reload the event log, rebuild progress, timing, and submission stats, refresh visible row signals, and refresh the “Suggested practice” popover. If IndexedDB is unavailable, the page falls back to the older single-tab localStorage projection behavior, but the normal supported path is event-log-backed and eventually consistent across tabs.

“Suggested practice” can also hold an immersive flow, but it is not list-order navigation. The user can start suggested flow from the “Suggested practice” popover or with Cmd+Option+Shift+F; the page first opens the current top recommendation and marks the flow state as suggested. After each full submit that returns Accepted, the page recomputes “Suggested practice” from the latest local submissions, timing, manual state, and current-session fatigue, then opens the new highest-ranked recommendation instead of the next visible row. That automatic recommendation jump follows the same title, statement, and editor framing rule as list flow. If route skipping is enabled for SQL or pure frontend problems, matching problems are removed from this candidate queue before selecting the top recommendation. The just-Accepted problem is not immediately recommended back to itself. If no recommendable problem exists, the page stays on the current problem and shows a status cue. Non-Accepted submits and passed sample runs never advance suggested flow.

The page also tracks a same-day one-shot Accepted combo. This combo is scoped to the Beijing calendar day and resets to zero at 00:00 Asia/Shanghai; the best historical combo is stored and shown separately. The unit is not a problem, but a fresh attempt that starts from the official default template or local fallback template. A fresh attempt starts when a problem is opened without a draft, when the current draft is reset, when the language switch recreates the default template, or when the Beijing-day draft rollover clears code back to defaults. An older problem that was already Accepted can therefore count again after its editor has returned to the default template and the user rewrites it.

A fresh attempt increases the same-day one-shot combo only when the user has made a meaningful code change from the template, no official-example run in that attempt has failed, no full submit in that attempt has failed, and the first full submit for that attempt returns Accepted. Running examples is optional; a direct full submit can count as long as no sample run failed before it. A failed sample run or failed full submit during a fresh attempt immediately breaks the current same-day combo and disqualifies that attempt from later combo credit, even if the user fixes the code and later gets Accepted. Extension installation errors, login errors, network failures, request timeouts, or other cases that do not return a final LeetCode judge result do not change the combo. After an attempt has already been counted, repeated Accepted submits, no-op submits, small edits, or later failures on the same unrestarted code are neutral: they neither increase nor break the combo. A new combo-eligible round requires returning to the default template first.

The one-shot combo UI belongs on the timing board beside the existing practice metrics and inside the active editor’s compact meter. The active editor signal must distinguish a one-shot candidate, a sample-failed round, a submit-failed round, a counted round, and a neutral repeat submit. Accepted combo increments trigger non-blocking reward feedback: the page may draw fireworks, light trails, record pulses, and randomized encouragement copy in a fixed overlay, but it must never steal focus, require confirmation, block typing, or move layout. The encouragement headline and subtitle must use the same default PingFang-first text stack as the rest of the practice UI, even when the fixed overlay is created dynamically. Reward intensity should scale from ordinary combo increments, to milestone counts, to very prominent new-record celebrations. Reduced-motion users should receive a quieter static cue instead of heavy particle animation.

The badge wall has 99 badges and counts only full LeetCode submissions initiated from this page, and only after LeetCode returns Accepted. Manual Done, Review, and Mastered state, passed sample runs, opened problem links, and historical LeetCode submissions do not count. Badge unlocks are also written to the same IndexedDB event log as achievement-unlocked events. The page derives badge progress from real submit, timing, topic-tag, and one-shot projections, then appends an unlock event for any completed badge that has not been recorded yet. The badge entry sits after the search field as a compact button; hover, focus, or click opens a game-style badge wall. Ordinary locked badges show their title, progress, and condition. Hidden locked badges render as ??? with only a vague hint, and show their real title and description only after unlock. Unlock feedback must be limited to a non-blocking toast or button pulse; it must not steal editor focus or change the problem-list layout. Endgame badges should cover extremely difficult goals such as every problem Accepted, every difficulty completed, a full-year Accepted streak, a hundred-problem day, and complete topic tracks.

Full submissions and official-example runs made through this page also append to a separate local submission-stat store. The store does not import historical LeetCode records; it only records actions initiated from the local editor after this feature exists. For each problem it tracks submit attempts, Accepted count, failed submit count, failed sample-run count, latest code size, Accepted time, average Accepted time, and time per 10 nonblank code lines. A compact “Suggested practice” button opens a hover/focus popover, and its ranking is modeled as browser-local practice scheduling instead of a single weakness score.

The final “Suggested practice” score is still clamped to 0 to 100, but it is composed from five explainable parts: review due-ness, weakness, problem value, current fit, and fatigue penalty. Review due-ness estimates a local stability and retrievability for each problem. Full Accepted submissions, recent Accepted streaks, passed sample runs, and manual mastered state increase stability; failures, slow normalized Accepted time, and manual review state lower it. As days since last Accepted increase, retrievability falls and due-ness rises; problems without a full Accepted are treated as not having established stable memory yet. Weakness still uses missing full Accepted evidence, failed submissions, failed sample runs, slow Accepted time normalized by code size, and manual review state. Failed full submissions are stronger than failed sample runs, failure rates are smoothed, and failure counts grow with diminishing returns. Problem value comes from Top 888 frequency, Hot 100 membership, ByteDance company presence, recent ByteDance buckets, tag coverage, LingShen coverage, and related-problem centrality, so a low-value obscure problem does not permanently outrank a slightly weaker high-frequency core problem. Current fit uses the currently open problem, shared tags, related-problem links, and nearby difficulty to prefer same-route transfer or reasonable progression. Fatigue penalty lowers problems already Accepted today, already Accepted in the current session, or heavily overlapping with tags practiced today.

Before score sorting, the scheduler promotes any Hot 100 problem that has no full Accepted evidence above non-Hot 100 candidates. Those promoted Hot 100 problems still use the same scheduling score and tie-breakers to choose their internal order.

The scheduler also supports cold start. A problem can enter the recommendation queue without local submission stats when it is high frequency, in Hot 100, ByteDance-heavy, valuable for tag coverage, or manually marked for review. The popover shows the top ranked problems, final practice score, and the main reason. Problems with local submission evidence still show compact row signals. A collapsed footer note explains the five components, stability, retrievability, cold start, and tie-breakers. The highest score becomes the “Suggested practice” item, and top ranked problems can be opened directly from the popover. The popover also offers a “Start suggested flow” action that holds the recommendation flow. This ranking is intentionally heuristic and browser-local.

Direct LeetCode submission is implemented through the Chrome extension in extensions/leetcode-submit. The page sends only titleSlug, langSlug, and the current editor code through window.postMessage for run and submit; run may also send locally saved extra testcases. The content script forwards that request to the extension background. The background owns the LeetCode cookies, queries questionEditorData, runs official examples plus any saved extra testcases through interpret_solution, posts full submissions to LeetCode China, and returns the LeetCode submission or interpretation id quickly. The page then polls the extension with short check requests, and the extension checks /submissions/detail/{id}/check/ once per request. This avoids keeping a Manifest V3 message channel open while LeetCode is still running the job. For compatibility with already-loaded older unpacked extensions, the page also accepts a finished result returned by the initial run or submit response before sending check. The page also probes login-status when a practice editor opens. That response includes an extension feature version and capability list, so the page can tell whether the loaded unpacked extension is current and point stale or missing installs to the installation guide. Cookie values are never sent to page JavaScript or stored in the repo. If the extension is not installed, outdated, or the user is not logged in, the page shows that as status and keeps the local editor usable. The run result panel shows the exact testcase input sent to LeetCode, split into individual case tabs with parameter names from questionEditorData.metaData. After the run result arrives, each case shows its submitted code answer, expected output, and stdout when LeetCode exposes those arrays. The page keeps compile and runtime diagnostics outside the case tabs because those are not per-case facts. The run status is considered accepted only when all returned testcase counts pass. When full submission returns a failed testcase, the page shows the failing testcase, actual output, expected output, and compile or runtime diagnostics below the status line, then stores that testcase as an extra run case for the same problem unless the same normalized testcase is already saved. The open editor also lets the user type an extra testcase manually, inspect the saved extra cases for that problem, remove a single saved case, or clear the problem’s extra cases. Manual cases use the same normalized local store as failed-submit cases and are sent only with the next sample run, never with a full submit. Extra run cases reset on the next Beijing calendar day, so daily practice starts from the official examples again. The page footer also keeps always-visible links to the GitHub repository, extension directory, latest extension ZIP, feedback issues, and page spec. It must have comfortable bottom breathing room so the link row never sits flush against the page end or the viewport edge. The footer also includes a collapsed, beginner-oriented installation guide for loading or reloading this unpacked Chrome extension from a GitHub Release package or from the repository source; the practice editor links directly to this guide and to the stable latest-release download URL. Extension release tags are named leetcode-submit-v<manifest version>. Pushing such a tag packages extensions/leetcode-submit into leetcode-submit.zip and leetcode-submit-<version>.zip on the GitHub Release. Chrome still installs it as an unpacked extension, so the guide must say to download the ZIP, unzip it, load the unzipped folder through chrome://extensions, and reload that unpacked extension after updating the local folder.

Preview controls include approach, implementation, tags, and related problems. The statement is not a hover target; it lives above the open editor. Approach, implementation, and tag previews can be inspected temporarily by hover or pinned open by click. Hover previews should stay open while the pointer moves from the trigger into the floating content, then close after the pointer leaves that content; pinned previews close when the user clicks outside the preview or presses Escape. The implementation preview is the home for reference implementation ordering, final reference code, provenance state, and follow-ups. Reference implementation code may be committed to this repository and published through GitHub Pages. The current page starts with harvested recent accepted submissions for the highest-frequency rows, then fills the rest of the target set with public, attributed reference implementations. The implementation preview prefers C++ reference code and applies local C++ syntax highlighting. When a problem has multiple mainstream approaches, those implementations are shown in recommended order, following the source solution order where the source already separates Solution 1, Solution 2, and so on. Problems that are not C++ problems in LeetCode, such as SQL, JavaScript, Shell, or Pandas practice rows, show the matching official-language reference instead of pretending that a C++ submission exists.

Reference implementation coverage is generated and audited locally. The sync command is npm run sync:leetcode-implementations; it reads public solution packs and writes src/data/leetcode-implementation-generated.ts. The audit command is npm run check:leetcode-implementations; it fails if any target row has no implementation reference, if a row with an official C++ template has no C++ reference, or if a reference still contains placeholder TODO code. Current sources are recorded per implementation: recent personal accepted submissions, Doocs LeetCode (CC-BY-SA-4.0), kamyu104 LeetCode-Solutions (MIT), and a small set of generated-original fallbacks for sparse LCP/LCCI gaps. Every external reference keeps its source URL, source title, license label, language, and provenance label in the hover card.

Practice State

The site is static, so it cannot store a server-side solve counter. Practice state is stored in the visitor’s browser with local storage:

  1. Done marks that the problem has been attempted.
  2. Needs thought marks that it should be revisited.
  3. Mastered marks that it is currently fluent.

Clicked links use the browser’s visited-link behavior and an additional local visited mark, so links remain visually distinct on later visits in the same browser profile.

Preview Contract

The statement panel uses a short plain-text excerpt from the Chinese problem statement. Prompt-like boilerplate embedded in problem text is removed before rendering.

The approach preview has two layers:

  1. tag-driven study checks, each with a short answer;
  2. sourced company follow-ups, each with a short answer, company, and source.

The sourced company list is intentionally conservative. It is not a claim that other companies never asked the same follow-up; it only records what could be verified publicly.