diff --git a/.agents/skills/guides-update/SKILL.md b/.agents/skills/guides-update/SKILL.md new file mode 100644 index 00000000..f0d0c430 --- /dev/null +++ b/.agents/skills/guides-update/SKILL.md @@ -0,0 +1,35 @@ +--- +name: Guides Update +description: Skill for adding or updating educational algorithm guides, ensuring consistent patterns and simple explanations suitable for an 8-year-old. +--- + +# Guides Update Skill + +This skill is invoked when adding a new concept guide (like "prefix sum", "recursion", etc.) to the pattern guides section. + +## Workflow Process + +### 1. Identify and Structure +- When asked to add a new guide pattern, first check existing guides (e.g., `src/data/guides/recursion.ts`) to understand the layout and format. +- Ensure the guide data file is created in `src/data/guides/` and exposes a `content` markdown string. +- Create a corresponding page in `src/app/guides/patterns//page.tsx`. +- Register the new guide in `src/data/guidesData.ts` under the appropriate category or as a new category, ensuring the new category matches the `id` and structure of existing categories. +- **CRITICAL:** Add the new guide's `id` to the `PATTERN_IDS` array in `src/config/sidebarNav.ts` so it appears in the sidebar navigation! + +### 2. Implementation Rules & Standards + +When writing the content for the guide, rigidly follow these rules: + +1. **Simple Analogy First:** Always start with a relatable, real-world analogy. The explanation MUST be simple enough for an 8-year-old to understand (e.g., using piggy banks, Russian nesting dolls, lines at a movie theater). +2. **Engaging Formatting:** Use emojis, bold text for key terms, and clear headings to make the guide visually appealing and easy to read. +3. **Core Formula/Concept:** Clearly outline the core formula, rules, or strategy of the pattern after the analogy. +4. **Interactive Visualization Link:** Always include a markdown link to the interactive simulator visualization for the pattern. Format: `[Visualize in the Interactive Simulator](viz:)`. +5. **Multi-Language Code Examples:** Provide complete, working code implementations in Python, Java, C++, and TypeScript. Use clear, educational variable names. **Crucially, all code blocks (the solution viewer codes) must be well-commented at a moderate rate so the user can easily understand what each line or block does.** +6. **Problem Walkthroughs:** Include at least one common problem walkthrough (e.g., Range Sum Query, Climbing Stairs) showing how to apply the pattern. +7. **Common Mistakes:** Add a section explicitly listing common pitfalls or errors to watch out for (e.g., infinite loops, off-by-one errors). +8. **Practice Links:** End the guide with a list of related practice problems linked to the platform. + +### 3. Verification +- Verify that `guidesData.ts` has been correctly updated and has no syntax errors. +- Verify that the guide page route (`page.tsx`) correctly mounts `GuidesClient` with the metadata setup. +- Verify that the language uses plain English and avoids overly dense academic jargon. diff --git a/next-env.d.ts b/next-env.d.ts index 0c7fad71..2d5420eb 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,7 +1,7 @@ /// /// /// -import "./.next/dev/types/routes.d.ts"; +import "./.next/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/public/sitemap.xml b/public/sitemap.xml index 1da72483..73679bc2 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -2,943 +2,1033 @@ https://rulcode.com/ - 2026-05-27 + 2026-06-02 daily 1.0 https://rulcode.com/about - 2026-05-27 + 2026-06-02 monthly 0.5 https://rulcode.com/privacy - 2026-05-27 + 2026-06-02 monthly 0.5 https://rulcode.com/terms - 2026-05-27 + 2026-06-02 monthly 0.5 https://rulcode.com/content-rights - 2026-05-27 + 2026-06-02 monthly 0.5 https://rulcode.com/feedback - 2026-05-27 + 2026-06-02 monthly 0.5 https://rulcode.com/blind75 - 2026-05-27 + 2026-06-02 monthly 0.5 https://rulcode.com/blog - 2026-05-27 + 2026-06-02 monthly 0.5 - https://rulcode.com/problem/sliding-window-maximum - 2026-05-27 + https://rulcode.com/problem/bellman-ford + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/spiral-matrix - 2026-05-27 + https://rulcode.com/problem/add-and-search-word + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/car-fleet - 2026-05-27 + https://rulcode.com/problem/spiral-matrix + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/two-pointers - 2026-05-27 + https://rulcode.com/problem/gcd-euclidean + 2026-06-02 weekly 0.8 https://rulcode.com/problem/find-minimum-in-rotated-sorted-array - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/word-search - 2026-05-27 + https://rulcode.com/problem/longest-palindromic-substring + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/sieve-eratosthenes + 2026-06-02 weekly 0.8 https://rulcode.com/problem/rotate-image - 2026-05-27 + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/find-the-duplicate-number + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/task-scheduler + 2026-06-02 weekly 0.8 https://rulcode.com/problem/graph-dfs - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/insert-interval - 2026-05-27 + https://rulcode.com/problem/sliding-window-maximum + 2026-06-02 weekly 0.8 https://rulcode.com/problem/xor-trick - 2026-05-27 + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/last-stone-weight + 2026-06-02 weekly 0.8 https://rulcode.com/problem/sudoku-solver - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/reverse-linked-list - 2026-05-27 + https://rulcode.com/problem/maximum-product-subarray + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/meeting-rooms-ii - 2026-05-27 + https://rulcode.com/problem/subsets-ii + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/sum-of-two-integers - 2026-05-27 + https://rulcode.com/problem/non-overlapping-intervals + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/valid-parentheses - 2026-05-27 + https://rulcode.com/problem/reorder-list + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/matrix-path-dp - 2026-05-27 + https://rulcode.com/problem/palindrome-partitioning + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/gcd-euclidean - 2026-05-27 + https://rulcode.com/problem/k-closest-points-to-origin + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/matrix-path-dp + 2026-06-02 weekly 0.8 https://rulcode.com/problem/tarjans - 2026-05-27 + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/longest-increasing-subsequence + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/car-fleet + 2026-06-02 weekly 0.8 https://rulcode.com/problem/activity-selection - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/prims - 2026-05-27 + https://rulcode.com/problem/insert-interval + 2026-06-02 weekly 0.8 https://rulcode.com/problem/karatsuba - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/container-with-most-water - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/topological-sort - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/number-of-islands - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/manachers - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/add-and-search-word - 2026-05-27 + https://rulcode.com/problem/letter-combinations-of-a-phone-number + 2026-06-02 weekly 0.8 https://rulcode.com/problem/binary-lifting - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/non-overlapping-intervals - 2026-05-27 + https://rulcode.com/problem/longest-repeating-character-replacement + 2026-06-02 weekly 0.8 https://rulcode.com/problem/word-search-grid - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/lru-cache - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/3sum - 2026-05-27 + https://rulcode.com/problem/search-in-rotated-sorted-array + 2026-06-02 weekly 0.8 https://rulcode.com/problem/segment-tree - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/sieve-eratosthenes - 2026-05-27 + https://rulcode.com/problem/word-break-problem + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/two-pointers + 2026-06-02 weekly 0.8 https://rulcode.com/problem/subset-generation-bits - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/bellman-ford - 2026-05-27 + https://rulcode.com/problem/meeting-rooms + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/dfs-inorder - 2026-05-27 + https://rulcode.com/problem/distinct-subsequences + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/modular-exponentiation - 2026-05-27 + https://rulcode.com/problem/dfs-inorder + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/search-in-rotated-sorted-array - 2026-05-27 + https://rulcode.com/problem/modular-exponentiation + 2026-06-02 weekly 0.8 https://rulcode.com/problem/dutch-national-flag - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/graph-bfs - 2026-05-27 + https://rulcode.com/problem/same-tree + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/same-tree - 2026-05-27 + https://rulcode.com/problem/graph-bfs + 2026-06-02 weekly 0.8 https://rulcode.com/problem/dfs-preorder - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/huffman-encoding - 2026-05-27 + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/prefix-sum + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/binary-tree-level-order-traversal + 2026-06-02 weekly 0.8 https://rulcode.com/problem/floyd-warshall - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/best-time-to-buy-and-sell-stock - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/coin-change - 2026-05-27 + https://rulcode.com/problem/burst-balloons + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/top-k-frequent-elements - 2026-05-27 + https://rulcode.com/problem/coin-change + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/unique-paths - 2026-05-27 + https://rulcode.com/problem/3sum + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/group-anagrams - 2026-05-27 + https://rulcode.com/problem/unique-paths + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/invert-binary-tree - 2026-05-27 + https://rulcode.com/problem/reverse-linked-list + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/jump-game-ii - 2026-05-27 + https://rulcode.com/problem/invert-binary-tree + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/n-queens - 2026-05-27 + https://rulcode.com/problem/word-search + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/dijkstras - 2026-05-27 + https://rulcode.com/problem/jump-game-ii + 2026-06-02 weekly 0.8 https://rulcode.com/problem/number-of-1-bits - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/merge-intervals - 2026-05-27 + https://rulcode.com/problem/dijkstras + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/serialize-tree - 2026-05-27 + https://rulcode.com/problem/valid-parentheses + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/union-find - 2026-05-27 + https://rulcode.com/problem/serialize-tree + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/longest-palindromic-substring - 2026-05-27 + https://rulcode.com/problem/union-find + 2026-06-02 weekly 0.8 https://rulcode.com/problem/decode-ways - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/jump-game - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/union-by-rank - 2026-05-27 + https://rulcode.com/problem/valid-anagram + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/maximum-depth-of-binary-tree - 2026-05-27 + https://rulcode.com/problem/union-by-rank + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/valid-anagram - 2026-05-27 + https://rulcode.com/problem/group-anagrams + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/subtree-of-another-tree - 2026-05-27 + https://rulcode.com/problem/maximum-depth-of-binary-tree + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/binary-tree-level-order-traversal - 2026-05-27 + https://rulcode.com/problem/merge-k-sorted-lists + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/merge-k-sorted-lists - 2026-05-27 + https://rulcode.com/problem/gas-station + 2026-06-02 weekly 0.8 https://rulcode.com/problem/maximum-subarray - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/gas-station - 2026-05-27 + https://rulcode.com/problem/contains-duplicate + 2026-06-02 weekly 0.8 https://rulcode.com/problem/valid-palindrome - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/contains-duplicate - 2026-05-27 + https://rulcode.com/problem/design-twitter + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/combination-sum - 2026-05-27 + https://rulcode.com/problem/construct-binary-tree-from-preorder-and-inorder-traversal + 2026-06-02 weekly 0.8 https://rulcode.com/problem/rabin-karp - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/construct-binary-tree-from-preorder-and-inorder-traversal - 2026-05-27 + https://rulcode.com/problem/merge-intervals + 2026-06-02 weekly 0.8 https://rulcode.com/problem/factory-method-notification-system - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/lcs - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/alien-dictionary - 2026-05-27 + https://rulcode.com/problem/time-based-key-value-store + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/merge-k-lists - 2026-05-27 + https://rulcode.com/problem/alien-dictionary + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/implement-trie - 2026-05-27 + https://rulcode.com/problem/counting-bits + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/counting-bits - 2026-05-27 + https://rulcode.com/problem/merge-k-lists + 2026-06-02 weekly 0.8 https://rulcode.com/problem/kth-largest - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/knapsack-01 - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/reverse-bits - 2026-05-27 + https://rulcode.com/problem/implement-trie + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/trie - 2026-05-27 + https://rulcode.com/problem/combination-sum-ii + 2026-06-02 weekly 0.8 https://rulcode.com/problem/count-bits - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/lis - 2026-05-27 + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/trie + 2026-06-02 weekly 0.8 https://rulcode.com/problem/sparse-table - 2026-05-27 + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/n-queens + 2026-06-02 weekly 0.8 https://rulcode.com/problem/pacific-atlantic-water-flow - 2026-05-27 + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/top-k-frequent-elements + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/word-search-ii + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/combination-sum + 2026-06-02 weekly 0.8 https://rulcode.com/problem/kadanes-algorithm - 2026-05-27 + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/subtree-of-another-tree + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/prims + 2026-06-02 weekly 0.8 https://rulcode.com/problem/monotonic-stack - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/sliding-window - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/bfs-level-order - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/longest-substring-without-repeating-characters - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/encode-and-decode-strings - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/binary-tree-maximum-path-sum - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/palindromic-substrings - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/a-star - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/kruskals - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/interval-scheduling - 2026-05-27 + https://rulcode.com/problem/best-time-to-buy-and-sell-stock-with-cooldown + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/middle-node - 2026-05-27 + https://rulcode.com/problem/coin-change-ii + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/minimum-window-substring - 2026-05-27 + https://rulcode.com/problem/interval-scheduling + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/maximum-product-subarray - 2026-05-27 + https://rulcode.com/problem/middle-node + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/minimum-window-substring + 2026-06-02 weekly 0.8 https://rulcode.com/problem/two-sum - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/lowest-common-ancestor-of-bst - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/prefix-sum - 2026-05-27 + https://rulcode.com/problem/course-schedule + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/course-schedule - 2026-05-27 + https://rulcode.com/problem/sum-of-two-integers + 2026-06-02 weekly 0.8 https://rulcode.com/problem/validate-binary-search-tree - 2026-05-27 + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/reverse-bits + 2026-06-02 + weekly + 0.8 + + + https://rulcode.com/problem/meeting-rooms-ii + 2026-06-02 weekly 0.8 https://rulcode.com/problem/binary-search - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/climbing-stairs - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/clone-graph - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/lca - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/word-break - 2026-05-27 + https://rulcode.com/problem/graph-valid-tree + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/graph-valid-tree - 2026-05-27 + https://rulcode.com/problem/word-break + 2026-06-02 weekly 0.8 https://rulcode.com/problem/find-median-from-data-stream - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/kth-smallest-element-in-a-bst - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/rotate-array - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/detect-cycle-in-a-linked-list - 2026-05-27 + https://rulcode.com/problem/fenwick-tree + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/fenwick-tree - 2026-05-27 + https://rulcode.com/problem/detect-cycle-in-a-linked-list + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/cyclic-sort - 2026-05-27 + https://rulcode.com/problem/recover-bst + 2026-06-02 weekly 0.8 https://rulcode.com/problem/fast-slow-pointers - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/recover-bst - 2026-05-27 + https://rulcode.com/problem/cyclic-sort + 2026-06-02 weekly 0.8 https://rulcode.com/problem/merge-sorted-lists - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/edit-distance - 2026-05-27 + https://rulcode.com/problem/kth-largest-element-in-a-stream + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/word-search-ii - 2026-05-27 + https://rulcode.com/problem/edit-distance + 2026-06-02 weekly 0.8 https://rulcode.com/problem/longest-consecutive-sequence - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/partition-equal-subset - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/subsets - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/remove-nth-node-from-end-of-list - 2026-05-27 - weekly - 0.8 - - - https://rulcode.com/problem/longest-repeating-character-replacement - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/permutations - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/dfs-postorder - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/serialize-and-deserialize-binary-tree - 2026-05-27 - weekly - 0.8 - - - https://rulcode.com/problem/bst-insert - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/house-robber-ii - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/word-break-problem - 2026-05-27 + https://rulcode.com/problem/bst-insert + 2026-06-02 weekly 0.8 https://rulcode.com/problem/kmp - 2026-05-27 - weekly - 0.8 - - - https://rulcode.com/problem/number-of-connected-components-in-an-undirected-graph - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/product-of-array-except-self - 2026-05-27 + 2026-06-02 weekly 0.8 - https://rulcode.com/problem/longest-increasing-subsequence - 2026-05-27 + https://rulcode.com/problem/number-of-connected-components-in-an-undirected-graph + 2026-06-02 weekly 0.8 https://rulcode.com/problem/house-robber - 2026-05-27 - weekly - 0.8 - - - https://rulcode.com/problem/meeting-rooms - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/missing-number - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/longest-common-subsequence - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/merge-two-sorted-lists - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/set-matrix-zeroes - 2026-05-27 - weekly - 0.8 - - - https://rulcode.com/problem/reorder-list - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/problem/combinations - 2026-05-27 + 2026-06-02 weekly 0.8 https://rulcode.com/blog/master-blind-75-visual-algorithms - 2026-05-27 + 2026-06-02 weekly 0.7 https://rulcode.com/blog/lru-cache-complete-guide - 2026-05-27 + 2026-06-02 weekly 0.7 https://rulcode.com/blog/dynamic-programming-for-people-who-hate-dynamic-programming - 2026-05-27 + 2026-06-02 weekly 0.7 diff --git a/src/app/guides/GuidesClient.tsx b/src/app/guides/GuidesClient.tsx index 9f3c7f2d..74e47a6d 100644 --- a/src/app/guides/GuidesClient.tsx +++ b/src/app/guides/GuidesClient.tsx @@ -41,6 +41,36 @@ const SolutionViewer = dynamic( { ssr: false } ); +const TreeDiagram = dynamic( + () => import("@/components/visualizations/TreeDiagram").then((mod) => mod.TreeDiagram), + { ssr: false } +); + +const GraphDiagram = dynamic( + () => import("@/components/visualizations/GraphDiagram").then((mod) => mod.GraphDiagram), + { ssr: false } +); + +const ArrayDiagram = dynamic( + () => import("@/components/visualizations/ArrayDiagram").then((mod) => mod.ArrayDiagram), + { ssr: false } +); + +const LinkedListDiagram = dynamic( + () => import("@/components/visualizations/LinkedListDiagram").then((mod) => mod.LinkedListDiagram), + { ssr: false } +); + +const StackDiagram = dynamic( + () => import("@/components/visualizations/StackDiagram").then((mod) => mod.StackDiagram), + { ssr: false } +); + +const QueueDiagram = dynamic( + () => import("@/components/visualizations/QueueDiagram").then((mod) => mod.QueueDiagram), + { ssr: false } +); + import { AlgoLink } from "@/components/AlgoLink"; interface SolutionViewerBlock { @@ -233,9 +263,13 @@ export default function GuidesClient({ guide }: GuidesClientProps) { "arrays-hashing", "two-pointers", "frequency-counter", + "prefix-sum", "sliding-window", "stack", "binary-search", + "recursion", + "backtracking", + "merge-intervals", ]; // Helper to compute the correct guide URL based on category @@ -555,6 +589,9 @@ export default function GuidesClient({ guide }: GuidesClientProps) { ); }, + pre({ children }: any) { + return <>{children}; + }, code({ node, inline, className, children, ...props }: any) { const match = /language-(\w+)/.exec(className || ""); const codeString = String(children).replace(/\n$/, ""); @@ -569,6 +606,35 @@ export default function GuidesClient({ guide }: GuidesClientProps) { if (!inline && match) { const lang = match[1]; + + if (lang === "tree") { + return ; + } + + if (lang === "graph" || lang === "trie") { + return ; + } + + if (lang === "array") { + return ; + } + + if (lang === "linkedlist" || lang === "singly-linkedlist") { + return ; + } + + if (lang === "doubly-linkedlist") { + return ; + } + + if (lang === "stack") { + return ; + } + + if (lang === "queue") { + return ; + } + return (
@@ -777,6 +843,7 @@ export default function GuidesClient({ guide }: GuidesClientProps) { value} > {block.content} diff --git a/src/app/guides/patterns/prefix-sum/page.tsx b/src/app/guides/patterns/prefix-sum/page.tsx new file mode 100644 index 00000000..fa11be89 --- /dev/null +++ b/src/app/guides/patterns/prefix-sum/page.tsx @@ -0,0 +1,34 @@ +import { Metadata } from 'next'; +import { notFound } from 'next/navigation'; +import { guidesData } from '@/data/guidesData'; +import GuidesClient from '@/app/guides/GuidesClient'; + +export async function generateMetadata(): Promise { + const guide = guidesData.flatMap((c) => c.guides).find((g) => g.slug === "prefix-sum"); + + if (!guide) { + return { + title: 'Guide Not Found | RulCode', + }; + } + + return { + title: `${guide.title} - DSA Guide | RulCode`, + description: guide.description, + openGraph: { + title: `${guide.title} - DSA Guide | RulCode`, + description: guide.description, + url: `https://rulcode.com/guides/patterns/prefix-sum`, + }, + }; +} + +export default async function PrefixSumPage() { + const guide = guidesData.flatMap((c) => c.guides).find((g) => g.slug === "prefix-sum"); + + if (!guide) { + notFound(); + } + + return ; +} diff --git a/src/components/visualizations/ArrayDiagram.tsx b/src/components/visualizations/ArrayDiagram.tsx new file mode 100644 index 00000000..96841821 --- /dev/null +++ b/src/components/visualizations/ArrayDiagram.tsx @@ -0,0 +1,60 @@ +import React, { useMemo } from 'react'; + +interface ArrayDiagramProps { + data: string; + className?: string; +} + +export const ArrayDiagram: React.FC = ({ data, className = "" }) => { + const arrayData = useMemo(() => { + try { + const parsed = JSON.parse(data.trim()); + if (Array.isArray(parsed)) return parsed; + } catch { + // fallback for plain comma separated values if JSON.parse fails + const cleaned = data.replace(/[\[\]]/g, '').trim(); + if (cleaned) { + return cleaned.split(',').map(s => { + const str = s.trim(); + const num = Number(str); + return isNaN(num) ? str.replace(/['"]/g, '') : num; + }); + } + } + return []; + }, [data]); + + if (arrayData.length === 0) { + return ( +
+ Invalid or Empty Array +
+ ); + } + + return ( +
+
+ {arrayData.map((val, idx) => ( +
+
+ {val} +
+ + {idx} + +
+ ))} +
+
+ ); +}; diff --git a/src/components/visualizations/LinkedListDiagram.tsx b/src/components/visualizations/LinkedListDiagram.tsx new file mode 100644 index 00000000..6c1e9cd9 --- /dev/null +++ b/src/components/visualizations/LinkedListDiagram.tsx @@ -0,0 +1,85 @@ +import React, { useMemo } from 'react'; +import { ArrowRight, ArrowLeftRight } from 'lucide-react'; + +interface LinkedListDiagramProps { + data: string; + className?: string; + doubly?: boolean; +} + +export const LinkedListDiagram: React.FC = ({ data, className = "", doubly = false }) => { + const listData = useMemo(() => { + try { + const parsed = JSON.parse(data.trim()); + if (Array.isArray(parsed)) return parsed; + } catch { + const cleaned = data.replace(/[\[\]]/g, '').trim(); + if (cleaned) { + return cleaned.split(',').map(s => { + const str = s.trim(); + const num = Number(str); + return isNaN(num) ? str.replace(/['"]/g, '') : num; + }); + } + } + return []; + }, [data]); + + if (listData.length === 0) { + return ( +
+ Invalid or Empty Linked List +
+ ); + } + + return ( +
+
+ {listData.map((val, idx) => ( + +
+
+ {/* Node Data part */} +
+
+ {val} +
+ {/* The "Next" pointer box part */} +
+
+
+
+
+ {idx === 0 && ( + + Head + + )} +
+ + {idx < listData.length - 1 && ( +
+ {doubly ? ( + + ) : ( + + )} +
+ )} + + {idx === listData.length - 1 && ( +
+ + null +
+ )} + + ))} +
+
+ ); +}; diff --git a/src/components/visualizations/QueueDiagram.tsx b/src/components/visualizations/QueueDiagram.tsx new file mode 100644 index 00000000..2419467b --- /dev/null +++ b/src/components/visualizations/QueueDiagram.tsx @@ -0,0 +1,88 @@ +import React, { useMemo } from 'react'; +import { ArrowDown, ArrowUp } from 'lucide-react'; + +interface QueueDiagramProps { + data: string; + className?: string; +} + +export const QueueDiagram: React.FC = ({ data, className = "" }) => { + const queueData = useMemo(() => { + try { + const parsed = JSON.parse(data.trim()); + if (Array.isArray(parsed)) return parsed; + } catch { + const cleaned = data.replace(/[\[\]]/g, '').trim(); + if (cleaned) { + return cleaned.split(',').map(s => { + const str = s.trim(); + const num = Number(str); + return isNaN(num) ? str.replace(/['"]/g, '') : num; + }); + } + } + return []; + }, [data]); + + if (queueData.length === 0) { + return ( +
+ Invalid or Empty Queue +
+ ); + } + + return ( +
+
+ + {/* Top Pointers Layer (Rear for Enqueue) */} +
+ {queueData.map((_, idx) => ( +
+ {idx === queueData.length - 1 && ( +
+ Rear + +
+ )} +
+ ))} +
+ + {/* The Queue Pipe */} +
+ {queueData.map((val, idx) => ( +
+
+ {val} +
+
+ ))} +
+ + {/* Bottom Pointers Layer (Front for Dequeue) */} +
+ {queueData.map((_, idx) => ( +
+ {idx === 0 && ( +
+ + Front +
+ )} +
+ ))} +
+ +
+
+ ); +}; diff --git a/src/components/visualizations/StackDiagram.tsx b/src/components/visualizations/StackDiagram.tsx new file mode 100644 index 00000000..30e914b0 --- /dev/null +++ b/src/components/visualizations/StackDiagram.tsx @@ -0,0 +1,74 @@ +import React, { useMemo } from 'react'; +import { ArrowLeft } from 'lucide-react'; + +interface StackDiagramProps { + data: string; + className?: string; +} + +export const StackDiagram: React.FC = ({ data, className = "" }) => { + const stackData = useMemo(() => { + try { + const parsed = JSON.parse(data.trim()); + if (Array.isArray(parsed)) return parsed; + } catch { + const cleaned = data.replace(/[\[\]]/g, '').trim(); + if (cleaned) { + return cleaned.split(',').map(s => { + const str = s.trim(); + const num = Number(str); + return isNaN(num) ? str.replace(/['"]/g, '') : num; + }); + } + } + return []; + }, [data]); + + if (stackData.length === 0) { + return ( +
+ Invalid or Empty Stack +
+ ); + } + + // We render the stack top-to-bottom, so we reverse the array for display + const reversedData = [...stackData].reverse(); + + return ( +
+
+ {/* The Stack Bucket */} +
+ {reversedData.map((val, idx) => ( +
+
+ {val} +
+ + {/* Top Pointer */} + {idx === 0 && ( +
+ + Top +
+ )} +
+ ))} + + {/* Ghost element to represent bottom when animating, or just spacing */} + {reversedData.length === 0 && ( +
+ )} +
+
+
+ ); +}; diff --git a/src/config/sidebarNav.ts b/src/config/sidebarNav.ts index be87ce1e..74617626 100644 --- a/src/config/sidebarNav.ts +++ b/src/config/sidebarNav.ts @@ -17,6 +17,7 @@ export const PATTERN_IDS = [ "arrays-hashing", "two-pointers", "frequency-counter", + "prefix-sum", "sliding-window", "stack", "binary-search", diff --git a/src/data/guides/arrays-hashing.ts b/src/data/guides/arrays-hashing.ts index 620a20d4..1cef8838 100644 --- a/src/data/guides/arrays-hashing.ts +++ b/src/data/guides/arrays-hashing.ts @@ -33,6 +33,10 @@ A **Static Array** is like a row of toy cubbies made of solid wood that can neve * **Random Access**: Because the cubbies are glued side-by-side, the computer can instantly jump to any cubby index. If each cubby is 4 inches wide, to look at cubby #3, the computer does a quick math: \`Start Address + (Index * Width)\`. For index 3: \`1000 + (3 * 4) = 1012\`. This calculation takes a tiny fraction of a second: \`O(1)\` time! * **Insertion and Deletion**: Adding or removing toys in the middle is slow. If you want to squeeze a new toy into Cubby #1, you must first move the toy in Cubby #1 to Cubby #2, the toy in Cubby #2 to Cubby #3, and so on, to make room! Shifting all those toys takes linear time: \`O(n)\`. +\`\`\`array +[10, 20, 30, 40, 50] +\`\`\` + ### 2. Dynamic Arrays (The Stretchy Cubbies) Since solid wood cubbies cannot grow, modern programming languages give us **Dynamic Arrays** (like Python lists or JavaScript arrays). * **Under the Hood**: A dynamic array starts as a small static array. When you add too many toys and run out of space, the computer magically creates a **brand new set of cubbies that is twice as large**, copies all your old toys into the new cubbies, and throws the old set away! @@ -108,6 +112,8 @@ When you need to compare two groups of items, count occurrences, or find duplica #### Valid Anagram Given two strings \`S\` and \`T\`, return \`true\` if \`T\` is an anagram of \`S\`, and \`false\` otherwise. +[Visualize Valid Anagram in the Interactive Simulator](viz:valid-anagram) + ##### Python \`\`\`python def is_anagram(s: str, t: str) -> bool: @@ -245,6 +251,8 @@ function isAnagram(s: string, t: string): boolean { When searching for a pair of numbers that satisfy an equation (like \`A + B = Target\`), you can rewrite the equation as \`B = Target - A\`. As you iterate through the array, treat the current element as \`A\`. Calculate the complement \`B\` and check if you have already stored \`B\` in your Hash Map. If yes, you have found the pair. If no, add \`A\` to the Hash Map. +[Visualize Two Sum in the Interactive Simulator](viz:two-sum) + #### Two Sum Find the indexes of the two numbers that add up to \`target\`. @@ -368,6 +376,8 @@ Current Sum - Past Sum = K ==> Past Sum = Current Sum - K #### Subarray Sum Equals K +[Visualize Prefix Sum in the Interactive Simulator](viz:prefix-sum) + ##### Python \`\`\`python def subarray_sum(nums: List[int], k: int) -> int: diff --git a/src/data/guides/backtracking.ts b/src/data/guides/backtracking.ts index 61762d4d..bcded074 100644 --- a/src/data/guides/backtracking.ts +++ b/src/data/guides/backtracking.ts @@ -376,9 +376,6 @@ Always remember: if you add something to an array before you explore, you MUST \ ## ๐ŸŽฎ Practice Problems & Website Verifications Verify your backtracking logic by solving these interactive problems on our platform: -* [Subsets](/problem/subsets) โ€” The fundamental "Include or Skip" backtracking template. -* [Permutations](/problem/permutations) โ€” Master the "Loop and Skip Already Used" backtracking template. * [Combination Sum](/problem/combination-sum) โ€” Learn to backtrack with an unlimited supply of elements. -* [N-Queens](/problem/n-queens) โ€” The ultimate test of board-state backtracking and 2D constraint checking. * [Word Search](/problem/word-search) โ€” Practice backtracking through a 2D grid of characters. `; diff --git a/src/data/guides/core-data-structures.ts b/src/data/guides/core-data-structures.ts index 1e6bd193..4492568d 100644 --- a/src/data/guides/core-data-structures.ts +++ b/src/data/guides/core-data-structures.ts @@ -1,5 +1,5 @@ export const content = ` -# Core Data Structures Overview +# Core Data Structures ## Introduction: The Magical Toy Playroom @@ -25,6 +25,10 @@ Imagine a long row of toy cubbies glued together in a straight line. Each cubby * **Adding things**: What if you want to squeeze a new cubby right in the middle? You can't! Since they are glued together, you have to move all the toys in the cubbies to the right by one slot to make space, which takes a lot of work (\`O(n)\`). * **Running out of space**: If you fill up all the cubbies and want more, you have to buy a whole new, bigger set of cubbies and copy all your toys over to the new row! +\`\`\`array +[10, 20, 30, 40, 50] +\`\`\` + ### ๐Ÿ’ป Array Deep Dive (For Older Coders) An **Array** is a contiguous block of memory cells. Contiguous means the cells are placed directly next to each other in memory, with absolutely no gaps. @@ -40,6 +44,8 @@ However, this static layout has trade-offs. If you want to insert a new element | **Insert / Delete at End** | O(1) (Amortized) | Fast push/pop, occasional memory reallocation. | | **Insert / Delete in Middle** | O(n) | Must shift all subsequent elements to maintain continuity. | +[Visualize Binary Search Array](viz:binary-search) + ### Code Implementations: Array #### Python @@ -105,6 +111,10 @@ Imagine you are on a birthday treasure hunt! You start at the first clue card un * **Finding things**: To find the 5th toy, you *must* start at the first card and follow them one by one. You cannot skip! That takes time (\`O(n)\`). * **Adding/Removing**: It is super easy to add a new clue card in the middle! You don't slide any toys around. You just rewrite the note on one card to point to your new card, and make your new card point to the next one. It takes just one quick step (\`O(1)\`). +\`\`\`linkedlist +[5, 10, 15, 20, 25] +\`\`\` + ### ๐Ÿ’ป Linked List Deep Dive (For Older Coders) A **Linked List** is a non-contiguous sequence of **Nodes**. Each node contains a value (the data) and a pointer reference (\`next\`) containing the memory address of the next node. Because nodes are scattered anywhere in memory, we do not have index offsets. Accessing the N-th node requires traversing the links sequentially from the head, resulting in **\`O(n)\` linear access time**. @@ -117,6 +127,8 @@ The huge advantage of linked lists is pointer flexibility. If you want to insert | **Insert / Delete at Head** | O(1) | Instant link update, no elements shifted. | | **Insert / Delete at Pointer** | O(1) | Re-routing references takes constant steps. | +[Visualize Middle of Linked List](viz:middle-node) + ### Code Implementations: Linked List #### Python @@ -272,6 +284,8 @@ What if two different keys generate the same number? This is called a **Hash Col | **Delete Key Entry** | O(1) | Locates index bucket and removes element. | | **Worst-Case Operations** | O(n) | Occurs during hash collision storms when many keys map to the same bucket. | +[Visualize Two Sum](viz:two-sum) + ### Code Implementations: Hash Map #### Python @@ -389,6 +403,10 @@ Imagine a high stack of warm, delicious chocolate-chip pancakes! * **Removing**: When you want to eat one, you must take the pancake sitting on the very top of the pile (we call this **Pop**). * **The Rule**: If you try to pull a pancake out from the middle or the bottom, the whole tower collapses! In computer science, we call this **Last-In, First-Out (LIFO)**. The last pancake made is the very first one you eat! +\`\`\`stack +["Bottom Pancake", "Middle Pancake", "Top Pancake"] +\`\`\` + ### ๐Ÿ’ป Stack Deep Dive (For Older Coders) A **Stack** is a linear structure governed by the **Last-In, First-Out (LIFO)** rule. The last element pushed onto the stack is the first element popped off. Because all operations are restricted to the head of the list, both \`push\` and \`pop\` execute in **\`O(1)\` constant time**. @@ -402,6 +420,8 @@ Stacks are critical in computers. The CPU uses a "Call Stack" to track active fu | **Peek (View Top Element)** | O(1) | Inspects top level without removal. | | **Access / Search Middle** | O(n) | Requires popping all elements above it. | +[Visualize Valid Parentheses](viz:valid-parentheses) + ### Code Implementations: Stack #### Python @@ -541,6 +561,10 @@ Imagine you and your friends are waiting in a line for the giant, awesome water * **Waiting in line**: When a new kid arrives, they have to walk to the very back of the line (we call this **Enqueue**). No cutting in the middle is allowed! * **The Rule**: In computer science, we call this **First-In, First-Out (FIFO)**. The first kid who gets in line is the first one who gets to slide! +\`\`\`queue +["Kid A", "Kid B", "Kid C", "Kid D"] +\`\`\` + ### ๐Ÿ’ป Queue Deep Dive (For Older Coders) A **Queue** is a linear structure based on the **First-In, First-Out (FIFO)** principle. The first item inserted is the first item removed. Queues support two main operations: \`enqueue\` (adding to the back) and \`dequeue\` (removing from the front), both taking **\`O(1)\` time**. @@ -554,6 +578,8 @@ Queues are used in asynchronous environments (buffers, print jobs, routing syste | **Peek Front Element** | O(1) | Inspects the next element to dequeue. | | **Access / Search Middle** | O(n) | Requires dequeuing items in front. | +[Visualize BFS Level Order Traversal](viz:bfs-level-order) + ### Code Implementations: Queue #### Python @@ -755,6 +781,8 @@ We can peek at the minimum or maximum instantly in **\`O(1)\` time**. However, e | **Pop Min / Max** | O(log n) | Swaps root with last element, then sifts down. | | **Build Heap (from Array)** | O(n) | Bottom-up heapify runs in linear time. | +[Visualize Kth Largest Element in a Stream](viz:kth-largest-element-in-a-stream) + ### Code Implementations: Heap #### Python diff --git a/src/data/guides/frequency-counter.ts b/src/data/guides/frequency-counter.ts index 6089ea68..e7c09e7e 100644 --- a/src/data/guides/frequency-counter.ts +++ b/src/data/guides/frequency-counter.ts @@ -374,6 +374,8 @@ Frequency counters are highly efficient but can break due to language-specific m --- +[Visualize Top K Frequent Elements in the Interactive Simulator](viz:top-k-frequent-elements) + ## Practice Problems & Website Verifications Verify your frequency counter implementations with these interactive challenges: diff --git a/src/data/guides/graphs.ts b/src/data/guides/graphs.ts index 9a71c884..3b0ac0eb 100644 --- a/src/data/guides/graphs.ts +++ b/src/data/guides/graphs.ts @@ -67,6 +67,17 @@ A mapping where each vertex is associated with a list or set of its neighbors. T ##### Adjacency List Representation +\`\`\`graph +type = "adjacency-list" +data = [ + [1, 2], + [2, 3], + [3], + [] +] +\`\`\` +*(Nodes are represented as 0=A, 1=B, 2=C, 3=D for simplicity in the visualizer)* + ##### Python \`\`\`python # Adjacency List represented as a Dictionary of Lists @@ -141,37 +152,51 @@ To traverse a graph, we must visit its vertices. Since graphs can have loops, we Imagine you are exploring a web of secret hideouts in a giant playground! How do you visit every single hideout without getting lost in loops? You bring a bucket of green slime to mark each hideout you visit (we call this a **Visited Set** so we don't walk in circles forever!). -There are two fun ways to explore the web: +There are two main strategies to explore this web of hideouts: **Breadth-First Search (BFS)** and **Depth-First Search (DFS)**. + +--- + +### 1. Breadth-First Search (BFS): The Ripple in a Pond -#### Breadth-First Search (BFS): The Ripple in a Pond -Imagine dropping a pebble in a puddle of waterโ€”it creates ripples that spread outwards in growing circles. -* You start at your house. -* First, you visit all of your *direct* next-door neighbors. -* Next, you visit all of *their* next-door neighbors. -* You keep spreading outwards layer-by-layer. This is the **perfect** way to find the absolute shortest path to any hideout! +[Visualize Graph BFS](viz:graph-bfs) -#### Depth-First Search (DFS): The Deep Maze Explorer -Imagine exploring a deep, dark maze. -* You pick a path and walk **as far as you can possibly go** until you hit a dead end. -* Once you hit a wall, you walk back to the last intersection and try the other path! -* You explore deep before you explore wide. It is perfect for checking if a path exists or finding your way out of a maze! +Imagine dropping a pebble in a puddle of waterโ€”it creates ripples that spread outwards in growing circles. BFS works exactly like this! + +**How it works step-by-step:** +1. You start at your house (the starting node). +2. First, you visit all of your *direct* next-door neighbors (Level 1). +3. Next, you visit all of *their* next-door neighbors (Level 2). +4. You keep spreading outwards layer-by-layer. + +**Why we use it:** Because BFS searches everywhere 1 step away, then 2 steps away, and so on, it is the **perfect way to find the absolute shortest path** to any destination! + +**How we code it:** We use a **Queue** (a First-In-First-Out line, like waiting for a water slide). You get in line, visit a hideout, mark it as visited, and put all its unvisited neighbors at the back of the line! --- -### 1. Breadth-First Search (BFS) -BFS visits vertices level-by-level, radiating outwards from a starting node. -* **Application**: Finding the **shortest path** on unweighted graphs. -* **Mechanism**: Uses a **Queue** (First-In, First-Out) and a **Visited Set**. +### 2. Depth-First Search (DFS): The Deep Maze Explorer + +[Visualize Graph DFS](viz:graph-dfs) + +Imagine exploring a deep, dark maze. You don't spread out; you pick a direction and commit to it! -### 2. Depth-First Search (DFS) -DFS plunges deep into a path, exploring as far as possible down a branch before backtracking. -* **Application**: Cycle detection, finding connected components, path-finding. -* **Mechanism**: Uses **Recursion** (the call stack) and a **Visited Set**. +**How it works step-by-step:** +1. You pick a path and walk **as far as you can possibly go** until you hit a dead end. +2. Once you hit a wall, you walk back (this is called **backtracking**) to the last intersection. +3. From that intersection, you try the next unexplored path! +4. You explore deep before you explore wide. + +**Why we use it:** It is perfect for checking if a path exists between two places, solving mazes, or finding cycles (checking if you walked in a circle). + +**How we code it:** We use **Recursion** (a function calling itself) or a **Stack** (a Last-In-First-Out tower, like a stack of pancakes). You always explore the most recently discovered path first. + +--- ### Side-by-Side Comparison -| Metric | BFS | DFS | +| Metric | BFS (Breadth-First Search) | DFS (Depth-First Search) | | :--- | :--- | :--- | +| **Exploration Style** | Wide and shallow (Layer-by-layer) | Deep and narrow (Plunges to the bottom) | | **Data Structure** | Queue (FIFO) | Stack / Recursion (LIFO) | | **Memory Usage** | O(width) (stores all nodes of a level) | O(depth) (stores the recursion path) | | **Shortest Path** | Guaranteed to find the shortest path (unweighted) | Not guaranteed to find the shortest path | @@ -182,6 +207,8 @@ DFS plunges deep into a path, exploring as far as possible down a branch before ## Key Algorithmic Patterns ### Pattern 1: Grid BFS/DFS (The Island Problem) + +[Visualize Number of Islands](viz:number-of-islands) Many interview problems represent a graph as a 2D matrix (a grid) where cells are vertices and adjacent cells (Up, Down, Left, Right) are edges. A classic example is **Number of Islands**. * **The Strategy**: @@ -364,6 +391,8 @@ function numIslands(grid: string[][]): number { --- ### Pattern 2: Topological Sort (Kahn's Algorithm) + +[Visualize Topological Sort](viz:topological-sort) A **Directed Acyclic Graph (DAG)** has directed edges and no cycles. **Topological Sort** provides a linear ordering of vertices such that for every directed edge \`U -> V\`, vertex \`U\` comes before \`V\` in the ordering. * **Real-world Example**: Course scheduling. If Course A is a prerequisite for Course B, you must take A before B. * **Kahn's Algorithm**: @@ -582,6 +611,8 @@ function canFinishCourses(numCourses: number, prerequisites: number[][]): boolea ### Pattern 3: Shortest Path on Weighted Graphs (Dijkstra's Algorithm) +[Visualize Dijkstra's Algorithm](viz:dijkstras) + To find the shortest distance from a starting node to all other nodes in a weighted graph with non-negative weights, we use **Dijkstra's Algorithm**. It uses a **Min-Heap (Priority Queue)** to always explore the next node that has the absolute shortest path distance from the start. @@ -1157,6 +1188,14 @@ This means: * Course 0 must be taken before Course 1 (\`0 -> 1\`). * Course 1 must be taken before Course 2 (\`1 -> 2\`). +\`\`\`graph +type = "edge-list" +data = [ + [0, 1], + [1, 2] +] +\`\`\` + ##### 1. Initial State * In-degrees: \`{0: 0, 1: 1, 2: 1}\` * Adjacency list: \`{0: [1], 1: [2], 2: []}\` diff --git a/src/data/guides/linked-list.ts b/src/data/guides/linked-list.ts index affa2945..75704b91 100644 --- a/src/data/guides/linked-list.ts +++ b/src/data/guides/linked-list.ts @@ -41,8 +41,8 @@ Imagine a playground train where each car holds the hand of the car *behind* it. * If you are standing at car C, you cannot see or go back to car B because car C is only holding the hand of car D! * If you want to go back, you have to start all the way at the front of the train (**Head**) and walk forward again. -\`\`\` -[ Head ] -> [ Node A: Val 10 | Next ] -> [ Node B: Val 20 | Next ] -> [ Node C: Val 30 | null ] +\`\`\`linkedlist +[10, 20, 30] \`\`\` Here is the standard structural definition of a Singly Linked List Node: @@ -109,8 +109,8 @@ Imagine a train where every car holds the hands of *both* the car in front of it * **The Good Part**: If a car gets broken, you can unhook it and reconnect the other two cars instantly because you can look both ways! * **The Hard Part**: The train nodes are bigger (require more memory to store two pointers) and take twice as much work to hook up! -\`\`\` -[ Head ] <-> [ Node A: prev | Val 10 | next ] <-> [ Node B: prev | Val 20 | next ] <-> [ Tail ] +\`\`\`doubly-linkedlist +["Node A", "Node B"] \`\`\` * **Advantage**: If you have a reference to Node B, you can delete it in \`O(1)\` time because you can immediately inspect B's \`prev\` pointer to find Node A and change A's \`next\` pointer. @@ -147,6 +147,8 @@ Pointer manipulation is notoriously tricky. If you do not assign pointer links i ### 1. In-Place Reversal of a Singly Linked List +[Visualize Reverse Linked List](viz:reverse-linked-list) + This is the holy grail of basic pointer manipulation. The objective is to change the direction of every single pointer arrow in the list so that the tail becomes the new head. #### Analogy: Turning the Train Around @@ -361,6 +363,8 @@ Imagine two animals, a slow Tortoise and a fast Hare, running down our track. * **Finding a Cycle (Loop)**: Imagine the track goes in a circle. If the Hare and Tortoise run forever, the fast Hare will eventually catch up and lap the slow Tortoise from behind! If they collide, we know there is a loop in the track. If the Hare reaches a dead end, there is no loop. #### 1. Finding the Midpoint + +[Visualize Finding the Middle Node](viz:middle-node) If you have a list of length \`N\`, move the \`slow\` pointer 1 step at a time, and the \`fast\` pointer 2 steps at a time. By the time \`fast\` reaches the end of the list, \`slow\` will be pointing exactly at the midpoint node. * **Application**: Used in Merge Sort for Linked Lists, or checking if a list is a palindrome. @@ -368,6 +372,8 @@ If you have a list of length \`N\`, move the \`slow\` pointer 1 step at a time, [Practice Problem: Middle of the Linked List](/problem/middle-node) #### 2. Cycle Detection + +[Visualize Linked List Cycle Detection](viz:detect-cycle-in-a-linked-list) If a list has a cycle (meaning the last node points back to an earlier node, forming a loop), a single pointer will traverse it infinitely. If we use a \`slow\` and a \`fast\` pointer, the fast pointer will eventually loop around and collide with the slow pointer. If \`fast\` ever reaches \`null\`, the list has no cycles. @@ -488,6 +494,8 @@ When you are creating a new linked list (e.g., merging two sorted lists, adding To avoid this, we instantiate a **Dummy Node** (a node with placeholder data, like \`-1\`) to act as the temporary anchor at the start of our list. We build the list by appending to \`dummy.next\`. Once we are finished, the actual head of our list is simply \`dummy.next\`. #### Merging Two Sorted Lists Walkthrough + +[Visualize Merge Two Sorted Lists](viz:merge-two-sorted-lists) Let's see this in action for merging: * List 1: \`1 -> 3 -> 5 -> null\` * List 2: \`2 -> 4 -> 6 -> null\` diff --git a/src/data/guides/prefix-sum.ts b/src/data/guides/prefix-sum.ts new file mode 100644 index 00000000..7b5ea50e --- /dev/null +++ b/src/data/guides/prefix-sum.ts @@ -0,0 +1,291 @@ +export const content = ` +# Prefix Sum: The Magic Diary of Totals! + +## ๐Ÿท Introduction: The Piggy Bank Problem + +Imagine you have a piggy bank, and every day you put some coins in it. + +* **Day 1:** 3 coins +* **Day 2:** 2 coins +* **Day 3:** 4 coins +* **Day 4:** 1 coin +* **Day 5:** 5 coins + +If your friend asks, *"How many coins did you put in from Day 1 to Day 3?"*, you would have to add them up: \`3 + 2 + 4 = 9\`. + +Then your friend asks, *"How about from Day 2 to Day 5?"*. You have to add them up again: \`2 + 4 + 1 + 5 = 12\`. + +If your piggy bank had 100 days of coins, adding them up over and over again for different days would be super slow and make your brain hurt! + +What if there was a magic trick to find the answer instantly without doing all that adding? + +## ๐Ÿ“ The Magic Diary (Prefix Sum) + +Instead of just writing down how many coins you added each day, what if you kept a special diary? In this diary, you write down the **TOTAL** number of coins currently in the piggy bank at the end of each day! + +Let's make our special diary: +* **Day 1:** 3 coins -> **Total: 3** +* **Day 2:** 2 coins -> (3 + 2) = **Total: 5** +* **Day 3:** 4 coins -> (5 + 4) = **Total: 9** +* **Day 4:** 1 coin -> (9 + 1) = **Total: 10** +* **Day 5:** 5 coins -> (10 + 5) = **Total: 15** + +This special "Total Diary" is what programmers call a **Prefix Sum** array! + +## โœจ How to Use the Magic Diary + +Now, if your friend asks, *"How many coins did you add from Day 2 to Day 4?"* + +You don't need to add Day 2 + Day 3 + Day 4 anymore! You just do one simple math problem using your diary: + +1. Look at the total on **Day 4** (which is 10). This is all the coins from the very beginning. +2. We only want coins starting from Day 2, so we need to throw away the coins from Day 1. Look at the total on **Day 1** (which is 3). +3. Subtract them! \`10 - 3 = 7\` coins! + +You found the answer instantly! +**Formula:** \`Sum from Day A to Day B = Total at Day B - Total right before Day A\` + +--- + +## ๐Ÿฆธ Why Do We Need To Learn It? + +In computer programming, we often have huge lists (arrays) with millions of numbers. Sometimes, the computer gets asked thousands of questions like *"What is the sum of numbers from index 100 to index 5000?"* + +If the computer adds them up one by one every single time, it will take forever! (This is called **O(N)** time). + +But if we spend a little time at the beginning to build our "Magic Diary" (Prefix Sum array), we can answer any question instantly in just one step! (This is called **O(1)** time). It makes our programs lightning fast! + +--- + +## ๐Ÿงฎ Let's Look at Some Code! (Building the Diary) + +Let's write code to take a normal array of numbers and turn it into a Prefix Sum array. + +[Visualize Prefix Sum in the Interactive Simulator](viz:prefix-sum) + +#### Complete Implementations + +##### Python +\`\`\`python +def build_prefix_sum(nums: list[int]) -> list[int]: + # We make a new array for our diary, same size as nums + prefix = [0] * len(nums) + + # Day 1 total is just Day 1's coins + prefix[0] = nums[0] + + # For the rest of the days, add today's coins to yesterday's total + for i in range(1, len(nums)): + prefix[i] = prefix[i - 1] + nums[i] + + return prefix + +# Example: +# nums = [3, 2, 4, 1, 5] +# prefix = [3, 5, 9, 10, 15] +\`\`\` + +##### Java +\`\`\`java +class Solution { + public int[] buildPrefixSum(int[] nums) { + int n = nums.length; + // We make a new array for our diary + int[] prefix = new int[n]; + + // Day 1 total is just Day 1's coins + prefix[0] = nums[0]; + + // For the rest of the days, add today's coins to yesterday's total + for (int i = 1; i < n; i++) { + prefix[i] = prefix[i - 1] + nums[i]; + } + + return prefix; + } +} +\`\`\` + +##### C++ +\`\`\`cpp +class Solution { +public: + vector buildPrefixSum(vector& nums) { + int n = nums.size(); + // We make a new array for our diary + vector prefix(n); + + // Day 1 total is just Day 1's coins + prefix[0] = nums[0]; + + // For the rest of the days, add today's coins to yesterday's total + for (int i = 1; i < n; i++) { + prefix[i] = prefix[i - 1] + nums[i]; + } + + return prefix; + } +}; +\`\`\` + +##### TypeScript +\`\`\`typescript +function buildPrefixSum(nums: number[]): number[] { + const n = nums.length; + // We make a new array for our diary + const prefix = new Array(n).fill(0); + + // Day 1 total is just Day 1's coins + prefix[0] = nums[0]; + + // For the rest of the days, add today's coins to yesterday's total + for (let i = 1; i < n; i++) { + prefix[i] = prefix[i - 1] + nums[i]; + } + + return prefix; +} +\`\`\` + +--- + +## ๐Ÿงฉ Problem 1: Range Sum Query + +This is exactly like the piggy bank problem! You are given an array of numbers. Then, you will be asked many times to find the sum of numbers between two indices \`left\` and \`right\`. + +### The Strategy +1. First, build the Prefix Sum array (the magic diary). +2. When asked for the sum from \`left\` to \`right\`: + - If \`left\` is 0, just return \`prefix[right]\`. + - Otherwise, return \`prefix[right] - prefix[left - 1]\`. (Take the big total and subtract the part we don't want!) + +#### Complete Implementations + +##### Python +\`\`\`python +class NumArray: + def __init__(self, nums: list[int]): + # This list will act as our "magic diary" to store cumulative totals + self.prefix = [] + current_total = 0 + + # Loop through the numbers to build the prefix sum array + for num in nums: + current_total += num + self.prefix.append(current_total) + + def sumRange(self, left: int, right: int) -> int: + # If left is 0, we just need the total up to 'right', no subtraction needed + if left == 0: + return self.prefix[right] + + # Otherwise, take the big total at 'right' and subtract the part before 'left' + return self.prefix[right] - self.prefix[left - 1] +\`\`\` + +##### Java +\`\`\`java +class NumArray { + // Array to store our cumulative totals + int[] prefix; + + public NumArray(int[] nums) { + // Initialize our magic diary with the same length + prefix = new int[nums.length]; + prefix[0] = nums[0]; // First element is always just itself + + // Build the prefix sum by adding current number to previous total + for (int i = 1; i < nums.length; i++) { + prefix[i] = prefix[i - 1] + nums[i]; + } + } + + public int sumRange(int left, int right) { + // If left is 0, just return the total accumulated so far + if (left == 0) { + return prefix[right]; + } + // Subtract the unwanted sum that comes before our 'left' index + return prefix[right] - prefix[left - 1]; + } +} +\`\`\` + +##### C++ +\`\`\`cpp +class NumArray { +private: + // This vector will hold our pre-calculated running totals + vector prefix; +public: + NumArray(vector& nums) { + // Set the size to match the input array + prefix.resize(nums.size()); + prefix[0] = nums[0]; + + // Loop through and calculate the running sum at each step + for (int i = 1; i < nums.size(); i++) { + prefix[i] = prefix[i - 1] + nums[i]; + } + } + + int sumRange(int left, int right) { + // Base case: if we start from the very beginning + if (left == 0) return prefix[right]; + + // General case: subtract the prefix sum just before our left bound + return prefix[right] - prefix[left - 1]; + } +}; +\`\`\` + +##### TypeScript +\`\`\`typescript +class NumArray { + // Array that serves as our "magic diary" for quick lookups + private prefix: number[]; + + constructor(nums: number[]) { + this.prefix = new Array(nums.length); + this.prefix[0] = nums[0]; + + // Populate the diary with cumulative sums + for (let i = 1; i < nums.length; i++) { + this.prefix[i] = this.prefix[i - 1] + nums[i]; + } + } + + sumRange(left: number, right: number): number { + // If starting from index 0, the sum is directly in the diary at 'right' + if (left === 0) { + return this.prefix[right]; + } + + // Otherwise, take the big sum and subtract the sum of elements before 'left' + return this.prefix[right] - this.prefix[left - 1]; + } +} +\`\`\` + +--- + +## ๐Ÿšซ Common Mistakes + +1. **Off-by-One Errors**: When subtracting, remember to subtract \`prefix[left - 1]\`, NOT \`prefix[left]\`. If you subtract \`prefix[left]\`, you accidentally throw away the starting number too! +2. **Left is Zero**: If \`left\` is 0, \`left - 1\` is -1, which will crash your program. Always handle the \`left == 0\` case separately! + +--- + +## ๐Ÿ“š Summary +* **Prefix Sum** is like a magic diary that keeps track of a running total. +* It changes slow O(N) addition into lightning-fast O(1) subtraction. +* Formula: \`Sum(left, right) = Prefix[right] - Prefix[left - 1]\`. + +--- + +## ๐ŸŽฎ Practice Problems & Website Verifications + +Verify your prefix sum logic by solving these interactive problems on our platform: +* [Product of Array Except Self](/problem/product-of-array-except-self) โ€” Learn to use prefix and suffix arrays together! +* [Maximum Subarray](/problem/maximum-subarray) โ€” Kadane's algorithm, a variation of prefix sum logic. +`; diff --git a/src/data/guides/sliding-window.ts b/src/data/guides/sliding-window.ts index b01209cd..1ad2fe88 100644 --- a/src/data/guides/sliding-window.ts +++ b/src/data/guides/sliding-window.ts @@ -17,6 +17,8 @@ By only subtracting the one that left and adding the one that entered, you get t In computer science, **Sliding Window** is a neat optimization where we convert nested loops on arrays or strings into a single linear pass by sliding a frame represented by two pointers (\`left\` and \`right\`). +[Visualize Sliding Window in the Interactive Simulator](viz:sliding-window) + --- ## Anatomy of a Sliding Window @@ -341,6 +343,8 @@ Given two strings \`s\` and \`t\`, return the minimum window substring of \`s\` 4. Expand the window by moving \`right\` forward. If \`s[right]\` is a target character, increment its count in \`window\`. If its count matches \`countT\`, increment \`have\`. 5. While \`have == need\`, update the minimum window answer, then shrink the window from the left by removing \`s[left]\`, decrementing its count in \`window\`, and updating \`have\` if its count falls below target, then incrementing \`left\`. +[Visualize Minimum Window Substring in the Interactive Simulator](viz:minimum-window-substring) + #### Complete Implementations ##### Python diff --git a/src/data/guides/stack.ts b/src/data/guides/stack.ts index c54b6356..1261e7c3 100644 --- a/src/data/guides/stack.ts +++ b/src/data/guides/stack.ts @@ -20,12 +20,8 @@ A stack supports three primary operations, which are super fast and run in **\`O 2. **Pop**: Take the topmost Lego block off the tower. 3. **Peek / Top**: Peek at the color of the topmost Lego block without removing it. -\`\`\` -Push(10) Push(20) Pop() - | | | 20 | | | - | | ---> | 10 | ---> | 10 | - | 10 | | 10 | | 10 | - ------ ------ ------ +\`\`\`stack +[10, 20] \`\`\` --- @@ -75,6 +71,8 @@ Given a string containing just the characters \`'('\`, \`')'\`, \`'{'\`, \`'}'\` * **Pop** the top element from the stack and verify it matches the closing bracket type. If not, return \`false\`. 4. After the loop, if the stack is empty, return \`true\` (all brackets closed). Otherwise, return \`false\` (some opening brackets remained unclosed). +[Visualize Valid Parentheses in the Interactive Simulator](viz:valid-parentheses) + #### Complete Implementations ##### Python @@ -482,6 +480,128 @@ function nextGreaterElement(nums: number[]): number[] { --- +### Pattern 4: Advanced Monotonic Stack (Largest Rectangle in Histogram) + +The ultimate test of monotonic stack understanding is calculating the largest rectangular area in a histogram. + +#### The Strategy +Imagine a skyline of buildings (the histogram). For any given building, the maximum rectangle that can be formed using its full height is bounded by the first shorter building to its left, and the first shorter building to its right. +1. We maintain a stack of indices, ensuring the heights of these indices remain strictly in **increasing order**. +2. Loop through each bar. If we encounter a bar that is *shorter* than the bar at the top of our stack, we know we have found the **right boundary** for that taller bar! +3. We **pop** the top index. Its height is \`heights[popped_index]\`. Its **left boundary** is the new top of the stack (the nearest shorter bar to the left). Its **right boundary** is our current index \`i\`. +4. We calculate the area: \`height * (right_boundary - left_boundary - 1)\`. +5. We push the current index \`i\` onto the stack and repeat. +6. A dummy height of \`0\` at the end forces all remaining bars in the stack to pop and calculate their areas. + +[Visualize Monotonic Stack in the Interactive Simulator](viz:monotonic-stack) + +#### Complete Implementations + +##### Python +\`\`\`python +def largestRectangleArea(heights: list[int]) -> int: + max_area = 0 + stack = [] # Stores indices + + # We append a 0 to force all remaining bars in the stack to pop at the end + heights.append(0) + + for i in range(len(heights)): + # While stack is not empty and current bar is shorter than the top of stack + while stack and heights[i] < heights[stack[-1]]: + h = heights[stack.pop()] + # If stack is empty, the width extends from the beginning (0) to i + w = i if not stack else i - stack[-1] - 1 + max_area = max(max_area, h * w) + + stack.append(i) + + return max_area +\`\`\` + +##### Java +\`\`\`java +import java.util.Stack; + +public class Solution { + public int largestRectangleArea(int[] heights) { + int maxArea = 0; + Stack stack = new Stack<>(); + + for (int i = 0; i <= heights.length; i++) { + int currentHeight = (i == heights.length) ? 0 : heights[i]; + + // While stack is not empty and current bar is shorter than the top of stack + while (!stack.isEmpty() && currentHeight < heights[stack.peek()]) { + int h = heights[stack.pop()]; + // If stack is empty, the width extends from the beginning (0) to i + int w = stack.isEmpty() ? i : i - stack.peek() - 1; + maxArea = Math.max(maxArea, h * w); + } + stack.push(i); + } + + return maxArea; + } +} +\`\`\` + +##### C++ +\`\`\`cpp +#include +#include +#include + +class Solution { +public: + int largestRectangleArea(std::vector& heights) { + int maxArea = 0; + std::stack st; + + for (int i = 0; i <= heights.size(); i++) { + int currentHeight = (i == heights.size()) ? 0 : heights[i]; + + // While stack is not empty and current bar is shorter than the top of stack + while (!st.empty() && currentHeight < heights[st.top()]) { + int h = heights[st.top()]; + st.pop(); + // If stack is empty, the width extends from the beginning (0) to i + int w = st.empty() ? i : i - st.top() - 1; + maxArea = std::max(maxArea, h * w); + } + st.push(i); + } + + return maxArea; + } +}; +\`\`\` + +##### TypeScript +\`\`\`typescript +function largestRectangleArea(heights: number[]): number { + let maxArea = 0; + const stack: number[] = []; + + for (let i = 0; i <= heights.length; i++) { + const currentHeight = i === heights.length ? 0 : heights[i]; + + // While stack is not empty and current bar is shorter than the top of stack + while (stack.length > 0 && currentHeight < heights[stack[stack.length - 1]]) { + const h = heights[stack.pop()!]; + // If stack is empty, the width extends from the beginning (0) to i + const w = stack.length === 0 ? i : i - stack[stack.length - 1] - 1; + maxArea = Math.max(maxArea, h * w); + } + stack.push(i); + } + + return maxArea; +} +\`\`\` + +--- + ## Common Interview Pitfalls and Debugging Strategies Stack programming is simple but has several critical runtime traps: @@ -506,4 +626,5 @@ Deepen your stack optimization skills by practice solving these problems: * [Valid Parentheses](/problem/valid-parentheses) โ€” Standard matching brackets using LIFO push/pop. * [Min Stack](/problem/min-stack) โ€” Retrieve minimum elements in constant time with dual stack configurations. * [Daily Temperatures](/problem/daily-temperatures) โ€” Apply the monotonic index distance template. +* [Largest Rectangle in Histogram](/problem/largest-rectangle-in-histogram) โ€” Advanced monotonic stack boundary detection. `; diff --git a/src/data/guides/trees.ts b/src/data/guides/trees.ts index 9bfc0f32..d8b974c0 100644 --- a/src/data/guides/trees.ts +++ b/src/data/guides/trees.ts @@ -39,10 +39,8 @@ The two most common tree structures you will see in technical interviews are **B #### Analogy: Nests with Two Branches A tree is a **Binary Tree** if each bird nest has **at most two** branches growing under it (a Left nest and a Right nest). There are no rules about what toys go whereโ€”you can throw them in any nest you want! -\`\`\` - [ Root ] - / \ - [ Left ] [ Right ] +\`\`\`tree +["Root", "Left", "Right"] \`\`\` Here is the standard structural definition of a Binary Tree Node: @@ -147,35 +145,47 @@ All operations degrade to \`O(n)\`! This is why production systems use self-bala ## Tree Traversals: DFS vs. BFS -Because tree structures are non-linear, we have multiple paths to traverse them. We group traversals into **Depth-First Search (DFS)** and **Breadth-First Search (BFS)**. +Because tree structures are non-linear, we have multiple paths to traverse them. We group traversals into two main strategies: **Depth-First Search (DFS)** and **Breadth-First Search (BFS)**. + +--- ### 1. Depth-First Search (DFS) +[Visualize Inorder DFS](viz:dfs-inorder) + #### Analogy: Exploring a Deep Cave Imagine you are exploring a deep cave with multiple branches. In **Depth-First Search**, you pick one branch and walk **as deep as possible** until you hit a wall at the bottom. Only then do you walk back (backtrack) and try the next branch! -Depending on when we write down the name of the nest we are in, we have three orders: -* **Preorder** (Write name -> Left branch -> Right branch) + +**How we do it:** We usually use **Recursion** (a function magically calling itself) to remember where we left off. + +Depending on *when* we write down the name of the nest we are in, we have three orders: +* **Preorder** (Write name -> Left branch -> Right branch) โ€” *Great for copying a tree!* * **Inorder** (Left branch -> Write name -> Right branch) โ€” *This reads a BST in perfect sorted order, from smallest to biggest!* * **Postorder** (Left branch -> Right branch -> Write name) โ€” *Perfect for deleting a tree because you clean the children nests before the parent!* +--- + ### 2. Breadth-First Search (BFS) / Level Order Traversal +[Visualize BFS Level Order Traversal](viz:bfs-level-order) + #### Analogy: Ripples in a Puddle Imagine you drop a pebble in a puddle of water, and it creates ripples that spread outwards in circles. In **Breadth-First Search**, you visit nests **level-by-level**, starting at the top root nest, then checking all nests on the first level down, then all nests on the second level down, and so on. You spread out wide before going deep! +**How we do it:** We use a **Queue** (a line of people, First-In-First-Out). +1. We put the root nest in the line. +2. Then, we take it out, write its name, and put its children at the back of the line. +3. We keep doing this until the line is empty! + --- ## Walkthrough of BFS Level Order Traversal Let's trace a level order traversal of this binary tree: -\`\`\` - [3] - / \ - [9] [20] - / \ - [15] [7] +\`\`\`tree +[3, 9, 20, null, null, 15, 7] \`\`\` 1. **Start**: Push \`[3]\` into queue. Queue: \`[[3]]\`. @@ -448,6 +458,8 @@ function levelOrder(root: TreeNode | null): number[][] { ### 1. Invert a Binary Tree Inverting a binary tree (creating its mirror image) is the classic interview question. + +[Visualize Invert Binary Tree](viz:invert-binary-tree) * **Intuition**: Swap the left and right children of every node in the tree recursively. ##### Invert Tree Implementation @@ -545,6 +557,8 @@ We return root \`[4]\` which now points to \`7\` on the left and \`2\` on the ri ### 2. Lowest Common Ancestor (LCA) in a BST +[Visualize Lowest Common Ancestor in BST](viz:lowest-common-ancestor-of-bst) + The **Lowest Common Ancestor** of two nodes \`P\` and \`Q\` is the lowest node in the tree that has both \`P\` and \`Q\` as descendants. Because it is a BST, we can use the sorting property to find the LCA in a single pass without traversing the whole tree: diff --git a/src/data/guides/trie.ts b/src/data/guides/trie.ts index 0b147d62..263df6f1 100644 --- a/src/data/guides/trie.ts +++ b/src/data/guides/trie.ts @@ -48,15 +48,14 @@ A Trie Node contains: #### Visualizing a Trie containing "cat", "cab", and "car" -\`\`\` - [ Root ] - | - (c) - | - (a) - / | \ - (t) (b) (r) - * * * +\`\`\`trie +edges = [ + ["Root", "c"], + ["c", "a"], + ["a", "t"], + ["a", "b"], + ["a", "r"] +] \`\`\` *(Asterisk * denotes a node where \`isEndOfWord = true\`)* @@ -150,6 +149,8 @@ This compression dramatically reduces the node count and pointer overhead, speed A standard Trie supports four core operations: \`insert\`, \`search\`, \`startsWith\`, and \`delete\`. +[Visualize Trie Prefix Tree](viz:trie) + ### 1. Inserting a Word (\`insert\`) To insert a word of length \`L\`: 1. Start at the Root. diff --git a/src/data/guides/two-pointers.ts b/src/data/guides/two-pointers.ts index d50cbeac..746a5077 100644 --- a/src/data/guides/two-pointers.ts +++ b/src/data/guides/two-pointers.ts @@ -372,6 +372,8 @@ Given the head of a linked list, determine if the linked list has a cycle in it 4. If there is a cycle, the fast pointer will eventually wrap around and "lap" the slow pointer, meaning they will meet (\`slow == fast\`). 5. If there is no cycle, the fast pointer will hit the end of the list (\`null\`). +[Visualize Linked List Cycle Detection in the Interactive Simulator](viz:detect-cycle-in-a-linked-list) + #### Complete Implementations ##### Python diff --git a/src/data/guidesData.ts b/src/data/guidesData.ts index 8a5b0729..f50bac19 100644 --- a/src/data/guidesData.ts +++ b/src/data/guidesData.ts @@ -12,6 +12,7 @@ import { content as recursionContent } from "./guides/recursion"; import { content as backtrackingContent } from "./guides/backtracking"; import { content as coreDataStructuresContent } from "./guides/core-data-structures"; import { content as mergeIntervalsContent } from "./guides/merge-intervals"; +import { content as prefixSumContent } from "./guides/prefix-sum"; export interface RelatedQuestion { id: string; @@ -165,7 +166,7 @@ Here is an overview of Space Complexity, followed by the reference table of stan guides: [ { slug: "core-data-structures", - title: "Core Data Structures Overview", + title: "Core Data Structures", description: "High-level summary of Array, HashMap, Stack, Queue, Heap and when to use them.", category: "fundamentals", heroImage: "fundamentals-overview", @@ -174,7 +175,7 @@ Here is an overview of Space Complexity, followed by the reference table of stan role: "Senior SLB Engineer", linkedin: "https://linkedin.com/in/rkmahale" }, - visualizations: ["reverse-linked-list", "bfs-level-order", "monotonic-stack", "binary-search"], + visualizations: ["reverse-linked-list", "bfs-level-order", "monotonic-stack", "binary-search", "kth-largest-element-in-a-stream"], content: coreDataStructuresContent, questions: [ { id: "two-sum", name: "Two Sum", difficulty: "Easy" }, @@ -211,7 +212,7 @@ Here is an overview of Space Complexity, followed by the reference table of stan role: "Senior SLB Engineer", linkedin: "https://linkedin.com/in/rkmahale" }, - visualizations: ["dfs-inorder", "bfs-level-order", "lowest-common-ancestor-of-bst", "bst-insert"], + visualizations: ["dfs-inorder", "bfs-level-order", "lowest-common-ancestor-of-bst", "bst-insert", "invert-binary-tree"], content: treesContent, questions: [ { id: "invert-binary-tree", name: "Invert Binary Tree", difficulty: "Easy" }, @@ -248,7 +249,7 @@ Here is an overview of Space Complexity, followed by the reference table of stan role: "Senior SLB Engineer", linkedin: "https://linkedin.com/in/rkmahale" }, - visualizations: ["graph-dfs", "graph-bfs", "topological-sort", "dijkstras"], + visualizations: ["graph-dfs", "graph-bfs", "topological-sort", "dijkstras", "number-of-islands"], content: graphsContent, questions: [ { id: "number-of-islands", name: "Number of Islands", difficulty: "Medium" }, @@ -273,7 +274,7 @@ Here is an overview of Space Complexity, followed by the reference table of stan role: "Senior SLB Engineer", linkedin: "https://linkedin.com/in/rkmahale" }, - visualizations: ["prefix-sum", "top-k-frequent-elements"], + visualizations: ["prefix-sum", "top-k-frequent-elements", "rotate-array", "maximum-subarray"], content: arraysHashingContent, questions: [ { id: "two-sum", name: "Two Sum", difficulty: "Easy" }, @@ -299,7 +300,7 @@ Here is an overview of Space Complexity, followed by the reference table of stan role: "Senior SLB Engineer", linkedin: "https://linkedin.com/in/rkmahale" }, - visualizations: ["two-pointers", "dutch-national-flag", "container-with-most-water"], + visualizations: ["two-pointers", "dutch-national-flag", "container-with-most-water", "trapping-rain-water"], content: twoPointersContent, questions: [ { id: "valid-palindrome", name: "Valid Palindrome", difficulty: "Easy" }, @@ -325,7 +326,7 @@ Here is an overview of Space Complexity, followed by the reference table of stan role: "Senior SLB Engineer", linkedin: "https://linkedin.com/in/rkmahale" }, - visualizations: ["top-k-frequent-elements"], + visualizations: ["valid-anagram", "top-k-frequent-elements"], content: frequencyCounterContent, questions: [ { id: "valid-anagram", name: "Valid Anagram", difficulty: "Easy" }, @@ -335,6 +336,30 @@ Here is an overview of Space Complexity, followed by the reference table of stan } ] }, + { + id: "prefix-sum", + title: "Prefix Sum", + guides: [ + { + slug: "prefix-sum", + title: "Prefix Sum", + description: "Master the magic diary pattern for instant range queries and subarray sums.", + category: "prefix-sum", + heroImage: "prefix-sum", + author: { + name: "Rahul Mahale", + role: "Senior SLB Engineer", + linkedin: "https://linkedin.com/in/rkmahale" + }, + visualizations: ["prefix-sum"], + content: prefixSumContent, + questions: [ + { id: "product-of-array-except-self", name: "Product of Array Except Self", difficulty: "Medium" }, + { id: "maximum-subarray", name: "Maximum Subarray", difficulty: "Medium" } + ] + } + ] + }, { id: "sliding-window", title: "Sliding Window", @@ -375,12 +400,13 @@ Here is an overview of Space Complexity, followed by the reference table of stan role: "Senior SLB Engineer", linkedin: "https://linkedin.com/in/rkmahale" }, - visualizations: ["monotonic-stack", "lru-cache"], + visualizations: ["valid-parentheses", "monotonic-stack"], content: stackContent, questions: [ { id: "valid-parentheses", name: "Valid Parentheses", difficulty: "Easy" }, { id: "min-stack", name: "Min Stack", difficulty: "Medium" }, - { id: "daily-temperatures", name: "Daily Temperatures", difficulty: "Medium" } + { id: "daily-temperatures", name: "Daily Temperatures", difficulty: "Medium" }, + { id: "largest-rectangle-in-histogram", name: "Largest Rectangle in Histogram", difficulty: "Hard" } ] } ] @@ -400,7 +426,7 @@ Here is an overview of Space Complexity, followed by the reference table of stan role: "Senior SLB Engineer", linkedin: "https://linkedin.com/in/rkmahale" }, - visualizations: ["binary-search", "two-pointers"], + visualizations: ["binary-search"], content: binarySearchContent, questions: [ { id: "binary-search", name: "Binary Search", difficulty: "Easy" }, @@ -449,13 +475,11 @@ Here is an overview of Space Complexity, followed by the reference table of stan role: "Senior SLB Engineer", linkedin: "https://linkedin.com/in/rkmahale" }, - visualizations: ["subsets", "permutations", "n-queens", "sudoku-solver"], + visualizations: ["subsets", "permutations", "combination-sum"], content: backtrackingContent, questions: [ - { id: "subsets", name: "Subsets", difficulty: "Medium" }, - { id: "permutations", name: "Permutations", difficulty: "Medium" }, { id: "combination-sum", name: "Combination Sum", difficulty: "Medium" }, - { id: "n-queens", name: "N-Queens", difficulty: "Hard" } + { id: "word-search", name: "Word Search", difficulty: "Medium" } ] } ] diff --git a/src/utils/visualizationMapping.tsx b/src/utils/visualizationMapping.tsx index 5689abab..08c2c130 100644 --- a/src/utils/visualizationMapping.tsx +++ b/src/utils/visualizationMapping.tsx @@ -18,11 +18,14 @@ export const visualizationMap: Record = { 'merge-intervals': dynamic(() => import('@/components/visualizations/algorithms/MergeIntervalsVisualization').then(m => m.MergeIntervalsVisualization), { ssr: false }), 'interval-scheduling': dynamic(() => import('@/components/visualizations/algorithms/InsertIntervalVisualization').then(m => m.InsertIntervalVisualization), { ssr: false }), 'monotonic-stack': dynamic(() => import('@/components/visualizations/algorithms/MonotonicStackVisualization').then(m => m.MonotonicStackVisualization), { ssr: false }), + 'valid-parentheses': dynamic(() => import('@/components/visualizations/algorithms/ValidParenthesesVisualization').then(m => m.ValidParenthesesVisualization), { ssr: false }), + 'two-sum': dynamic(() => import('@/components/visualizations/algorithms/TwoSumVisualization').then(m => m.TwoSumVisualization), { ssr: false }), 'quick-select': dynamic(() => import('@/components/visualizations/algorithms/QuickSelectVisualization').then(m => m.QuickSelectVisualization), { ssr: false }), 'container-with-most-water': dynamic(() => import('@/components/visualizations/algorithms/ContainerWithMostWaterVisualization').then(m => m.ContainerWithMostWaterVisualization), { ssr: false }), 'trapping-rain-water': dynamic(() => import('@/components/visualizations/algorithms/TrappingRainWaterVisualization').then(m => m.TrappingRainWaterVisualization), { ssr: false }), 'rotate-array': dynamic(() => import('@/components/visualizations/algorithms/RotateArrayVisualization').then(m => m.RotateArrayVisualization), { ssr: false }), 'cyclic-sort': dynamic(() => import('@/components/visualizations/algorithms/CyclicSortVisualization').then(m => m.CyclicSortVisualization), { ssr: false }), + 'valid-anagram': dynamic(() => import('@/components/visualizations/algorithms/ValidAnagramVisualization').then(m => m.ValidAnagramVisualization), { ssr: false }), // Tree Algorithms 'dfs-preorder': dynamic(() => import('@/components/visualizations/algorithms/DFSPreorderVisualization').then(m => m.DFSPreorderVisualization), { ssr: false }), @@ -34,6 +37,7 @@ export const visualizationMap: Record = { 'lowest-common-ancestor-of-bst': dynamic(() => import('@/components/visualizations/algorithms/LowestCommonAncestorBSTVisualization').then(m => m.LowestCommonAncestorBSTVisualization), { ssr: false }), 'serialize-tree': dynamic(() => import('@/components/visualizations/algorithms/SerializeTreeVisualization').then(m => m.SerializeTreeVisualization), { ssr: false }), 'recover-bst': dynamic(() => import('@/components/visualizations/algorithms/RecoverBSTVisualization').then(m => m.RecoverBSTVisualization), { ssr: false }), + 'invert-binary-tree': dynamic(() => import('@/components/visualizations/algorithms/InvertBinaryTreeVisualization').then(m => m.InvertBinaryTreeVisualization), { ssr: false }), 'trie': dynamic(() => import('@/components/visualizations/algorithms/TrieVisualization').then(m => m.TrieVisualization), { ssr: false }), // Linked List Algorithms @@ -48,8 +52,9 @@ export const visualizationMap: Record = { 'merge-k-sorted-lists': dynamic(() => import('@/components/visualizations/algorithms/MergeKSortedListsVisualization').then(m => m.MergeKSortedListsVisualization), { ssr: false }), // Graph Algorithms - 'graph-dfs': dynamic(() => import('@/components/visualizations/algorithms/GraphDFSVisualization').then(m => m.GraphDFSVisualization), { ssr: false }), - 'graph-bfs': dynamic(() => import('@/components/visualizations/algorithms/GraphBFSVisualization').then(m => m.GraphBFSVisualization), { ssr: false }), + 'graph-dfs': dynamic(() => import('@/components/visualizations/GraphVisualization').then(m => m.GraphVisualization), { ssr: false }), + 'graph-bfs': dynamic(() => import('@/components/visualizations/GraphVisualization').then(m => m.GraphVisualization), { ssr: false }), + 'number-of-islands': dynamic(() => import('@/components/visualizations/algorithms/NumberOfIslandsVisualization').then(m => m.NumberOfIslandsVisualization), { ssr: false }), 'number-of-connected-components-in-an-undirected-graph': dynamic(() => import('@/components/visualizations/algorithms/NumberOfConnectedComponentsVisualization').then(m => m.NumberOfConnectedComponentsVisualization), { ssr: false }), 'pacific-atlantic-water-flow': dynamic(() => import('@/components/visualizations/algorithms/PacificAtlanticVisualization').then(m => m.PacificAtlanticVisualization), { ssr: false }), 'alien-dictionary': dynamic(() => import('@/components/visualizations/algorithms/AlienDictionaryVisualization').then(m => m.AlienDictionaryVisualization), { ssr: false }), @@ -138,6 +143,7 @@ export const visualizationMap: Record = { 'kth-largest-element-in-a-stream': dynamic(() => import('@/components/visualizations/algorithms/KthLargestElementInAStreamVisualization').then(m => m.KthLargestElementInAStreamVisualization), { ssr: false }), 'top-k-frequent-elements': dynamic(() => import('@/components/visualizations/algorithms/TopKFrequentElementsVisualization').then(m => m.TopKFrequentElementsVisualization), { ssr: false }), 'sliding-window-maximum': dynamic(() => import('@/components/visualizations/algorithms/SlidingWindowMaxVisualization').then(m => m.SlidingWindowMaxVisualization), { ssr: false }), + 'minimum-window-substring': dynamic(() => import('@/components/visualizations/algorithms/MinimumWindowSubstringVisualization').then(m => m.MinimumWindowSubstringVisualization), { ssr: false }), 'find-median-from-data-stream': dynamic(() => import('@/components/visualizations/algorithms/FindMedianFromDataStreamVisualization').then(m => m.FindMedianFromDataStreamVisualization), { ssr: false }), 'last-stone-weight': dynamic(() => import('@/components/visualizations/algorithms/LastStoneWeightVisualization').then(m => m.LastStoneWeightVisualization), { ssr: false }), 'k-closest-points-to-origin': dynamic(() => import('@/components/visualizations/algorithms/KClosestPointsVisualization').then(m => m.KClosestPointsVisualization), { ssr: false }), @@ -182,6 +188,18 @@ export const visualizationMetadataMap: RecordLoading visualization...
}> - + ); }