diff --git a/apps/docs/blume.config.ts b/apps/docs/blume.config.ts index c94f563..b26d8d5 100644 --- a/apps/docs/blume.config.ts +++ b/apps/docs/blume.config.ts @@ -142,11 +142,8 @@ export default defineConfig({ sidebar: { display: "flat", // "flat" | "group" | "page" }, - // The glossary is no content folder any more, so it is pinned above the - // sidebar tree, on every page and breakpoint. - featured: [ - { label: "Changelog", href: "/changelog", icon: "clock" }, - { label: "Appendix", href: "/appendix", icon: "library" }, - ], + // No `featured`: Blume renders it above the `Sidebar` slot, and the + // content-source selector must sit above the pinned links, so + // components/SourceSidebar.astro renders both (Changelog, Appendix). }, }); diff --git a/apps/docs/components.ts b/apps/docs/components.ts index ceee537..4914263 100644 --- a/apps/docs/components.ts +++ b/apps/docs/components.ts @@ -16,5 +16,8 @@ export default defineComponents({ layout: { // Topic landing pages' "what links here": every problem pointing at the page. PageFooter: "./components/BacklinksList.astro", + // Content-source selector + pinned links above the nav tree, scoped to the + // active source (sources.ts). + Sidebar: "./components/SourceSidebar.astro", }, }); diff --git a/apps/docs/components/SourceSidebar.astro b/apps/docs/components/SourceSidebar.astro new file mode 100644 index 0000000..dca6d9a --- /dev/null +++ b/apps/docs/components/SourceSidebar.astro @@ -0,0 +1,117 @@ +--- +/** + * The `Sidebar` slot (also the mobile drawer's nav, which defaults to it): a + * Fumadocs-style content-source selector, then the pinned links, then + * Blume's own nav tree scoped to the active source (`sources.ts`). + * + * The pinned links live here, not in `navigation.featured`: Blume renders + * featured links above this slot, so the selector could not sit over them. + * + * The selector is a `
` with Blume's `data-blume-dropdown` light + * dismiss (outside press, Escape, focus leaving), like its own NavSelector. + */ +import Icon from "blume/components/Icon.astro"; +import { withBase, withMountedBase } from "blume/components/islands/base-path.ts"; +import NavTree from "blume/components/layout/NavTree.astro"; +import type { UIStrings } from "blume/core/i18n-ui.ts"; +import { isUnderPath } from "blume/core/navigation.ts"; +import type { NavNode } from "blume/core/types.ts"; +import { SOURCES } from "../sources.ts"; + +interface Props { + items: NavNode[]; + currentRoute: string; + strings?: UIStrings["nav"]; + ids?: Map; + fragmentBase?: string; +} + +const PINNED = [ + { label: "Changelog", href: "/changelog", icon: "clock" }, + { label: "Appendix", href: "/appendix", icon: "library" }, +]; + +const { items, currentRoute, ...tree } = Astro.props; + +const active = + SOURCES.filter((s) => isUnderPath(currentRoute, s.path)).sort( + (a, b) => b.path.length - a.path.length, + )[0] ?? SOURCES[0]!; + +const claims = (node: NavNode, path: string) => { + const at = node.kind === "page" ? node.route : node.path; + return at !== undefined && isUnderPath(at, path); +}; + +// The root source keeps every node no other source claims; any other source +// shows its folder's children, as if that folder were the content root. +const scoped = + active.path === "/" + ? items.filter( + (node) => !SOURCES.some((s) => s.path !== "/" && claims(node, s.path)), + ) + : items.flatMap((node) => + node.kind === "group" && node.path === active.path ? node.children : [], + ); +--- + +
+ + + + + {active.label} + + + +
+ + + + + + diff --git a/apps/docs/content/(01-linear-structures)/monotonic-stack/901_online-stock-span.mdx b/apps/docs/content/(01-linear-structures)/monotonic-stack/901_online-stock-span.mdx new file mode 100644 index 0000000..7286338 --- /dev/null +++ b/apps/docs/content/(01-linear-structures)/monotonic-stack/901_online-stock-span.mdx @@ -0,0 +1,45 @@ +--- +title: '901. Online Stock Span' +description: Design an algorithm that collects daily price quotes for some stock and returns the span of that stock's price for the current day +icon: dot +topics: + - { name: "Stack", slug: "stack" } + - { name: "Design", slug: "design" } + - { name: "Monotonic Stack", slug: "monotonic-stack" } + - { name: "Data Stream", slug: "data-stream" } +issue: "https://github.com/prdlk/leetcode/issues/75" +sidebar: + label: 'Online Stock Span' + badge: 'Medium' +--- + +### Example 1: +- Input: `` +- Output: `` +- Explanation: Input ["StockSpanner", "next", "next", "next", "next", "next", "next", "next"] `[[]`, `[100]`, `[80]`, `[60]`, `[70]`, `[60]`, `[75]`, [85]] Output [null, `1`, `1`, `1`, `2`, `1`, `4`, 6] Explanation StockSpanner stockSpanner = new StockSpanner(); stockSpanner.next(100); // return `1` stockSpanner.next(80); // return `1` stockSpanner.next(60); // return `1` stockSpanner.next(70); // return `2` stockSpanner.next(60); // return `1` stockSpanner.next(75); // return `4`, because the last `4` prices (including today's `price` of `75`) were less than or equal to today's `price`. stockSpanner.next(85); // return `6` + +### Constraints: + +- `1 <= price <= 10^5` +- At most 10^4 calls will be made to next. + +## Solution + +```py +class StockSpanner: + def __init__(self): + self.stack = [] + + def next(self, price: int) -> int: + ans = 1 + while self.stack and self.stack[-1][0] <= price: + ans += self.stack.pop()[1] + + self.stack.append([price, ans]) + return ans + + +# Your StockSpanner object will be instantiated and called as such: +# obj = StockSpanner() +# param_1 = obj.next(price) +``` diff --git a/apps/docs/content/(01-linear-structures)/sliding-window/76_minimum-window-substring.mdx b/apps/docs/content/(01-linear-structures)/sliding-window/76_minimum-window-substring.mdx new file mode 100644 index 0000000..4f278fd --- /dev/null +++ b/apps/docs/content/(01-linear-structures)/sliding-window/76_minimum-window-substring.mdx @@ -0,0 +1,46 @@ +--- +title: '76. Minimum Window Substring' +description: Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no such substring, return the empty string "" +icon: dot +topics: + - { name: "Hash Table", slug: "hash-table" } + - { name: "String", slug: "string" } + - { name: "Sliding Window", slug: "sliding-window" } +issue: "https://github.com/prdlk/leetcode/issues/57" +sidebar: + label: 'Minimum Window Substring' + badge: 'Hard' +--- + +::::warning +Could you find an algorithm that runs in O(m + n) time? +:::: + +### Example 1: +- Input: `s = "ADOBECODEBANC", t = "ABC"` +- Output: `"BANC"` +- Explanation: The minimum window substring "BANC" includes 'A', 'B', and 'C' from string `t`. + +### Example 2: +- Input: `s = "a", t = "a"` +- Output: `"a"` +- Explanation: The entire string `s` is the minimum window. + +### Example 3: +- Input: `s = "a", t = "aa"` +- Output: `""` +- Explanation: Both 'a's from `t` must be included in the window. Since the largest window of `s` only has one 'a', return empty string. + +### Constraints: + +- `m == s.length` +- `n == t.length` +- `1 <= m, n <= 10^5` +- `s` and `t` consist of uppercase and lowercase English letters. + +## Solution + +```py +class Solution: + def minWindow(self, s: str, t: str) -> str: +``` diff --git a/apps/docs/content/(01-linear-structures)/stack/224_basic-calculator.mdx b/apps/docs/content/(01-linear-structures)/stack/224_basic-calculator.mdx new file mode 100644 index 0000000..4655e52 --- /dev/null +++ b/apps/docs/content/(01-linear-structures)/stack/224_basic-calculator.mdx @@ -0,0 +1,43 @@ +--- +title: '224. Basic Calculator' +description: Given a string s representing a valid expression, implement a basic calculator to evaluate it, and return the result of the evaluation +icon: dot +topics: + - { name: "Math", slug: "math" } + - { name: "String", slug: "string" } + - { name: "Stack", slug: "stack" } + - { name: "Recursion", slug: "recursion" } +issue: "https://github.com/prdlk/leetcode/issues/71" +sidebar: + label: 'Basic Calculator' + badge: 'Hard' +--- + +### Example 1: +- Input: `s = "1 + 1"` +- Output: `2` + +### Example 2: +- Input: `s = " 2-1 + 2 "` +- Output: `3` + +### Example 3: +- Input: `s = "(1+(4+5+2)-3)+(6+8)"` +- Output: `23` + +### Constraints: + +- `1 <= s.length <= 3 * 10^5` +- `s` consists of digits, '+', '-', '(', ')', and ' '. +- `s` represents a valid expression. +- '+' is not used as a unary operation (i.e., "+1" and "+(2 + 3)" is invalid). +- '-' could be used as a unary operation (i.e., "-1" and "-(2 + 3)" is valid). +- There will be no two consecutive operators in the input. +- Every number and running calculation will fit in a signed 32-bit integer. + +## Solution + +```py +class Solution: + def calculate(self, s: str) -> int: +``` diff --git a/apps/docs/content/system-design/index.mdx b/apps/docs/content/system-design/index.mdx new file mode 100644 index 0000000..b358405 --- /dev/null +++ b/apps/docs/content/system-design/index.mdx @@ -0,0 +1,27 @@ +--- +title: System Design +description: Notes for system design interviews — how to scope a problem, size it, and pick the parts that carry the load. +icon: network +sidebar: + label: Overview +--- + +## How an interview runs + + + + Pin down the functional requirements (what the system does) and the non-functional ones (latency, availability, consistency, scale) before drawing anything. + + + Size the traffic, storage and bandwidth with back-of-the-envelope numbers, so later choices have a reason. + + + Define the endpoints and the entities they read and write. + + + Draw the request path end to end: clients, load balancers, services, caches, stores and queues. + + + Take the hardest part (a hot key, fan-out, a consistency guarantee) and work through its tradeoffs. + + diff --git a/apps/docs/redirects.ts b/apps/docs/redirects.ts index 69a7b96..90906dd 100644 --- a/apps/docs/redirects.ts +++ b/apps/docs/redirects.ts @@ -29,6 +29,7 @@ export default [ { from: "/71", to: "/stack/simplify-path" }, { from: "/73", to: "/matrix-index-math/set-matrix-zeroes" }, { from: "/74", to: "/binary-search/search-a-2d-matrix" }, + { from: "/76", to: "/sliding-window/minimum-window-substring" }, { from: "/78", to: "/backtracking/subsets" }, { from: "/80", to: "/two-pointers/remove-duplicates-from-sorted-array-ii" }, { from: "/84", to: "/monotonic-stack/largest-rectangle-in-histogram" }, @@ -61,6 +62,7 @@ export default [ { from: "/211", to: "/trie/design-add-and-search-words-data-structure" }, { from: "/215", to: "/heap-priority-queue/kth-largest-element-in-an-array" }, { from: "/217", to: "/hash-table/contains-duplicate" }, + { from: "/224", to: "/stack/basic-calculator" }, { from: "/226", to: "/tree-dfs/invert-binary-tree" }, { from: "/230", to: "/binary-search-tree/kth-smallest-element-in-a-bst" }, { from: "/235", to: "/binary-search-tree/lowest-common-ancestor-of-a-binary-search-tree" }, @@ -89,6 +91,7 @@ export default [ { from: "/739", to: "/monotonic-stack/daily-temperatures" }, { from: "/853", to: "/monotonic-stack/car-fleet" }, { from: "/875", to: "/binary-search/koko-eating-bananas" }, + { from: "/901", to: "/monotonic-stack/online-stock-span" }, { from: "/973", to: "/heap-priority-queue/k-closest-points-to-origin" }, { from: "/974", to: "/prefix-sum/subarray-sums-divisible-by-k" }, { from: "/977", to: "/two-pointers/squares-of-a-sorted-array" }, diff --git a/apps/docs/sources.ts b/apps/docs/sources.ts new file mode 100644 index 0000000..413d017 --- /dev/null +++ b/apps/docs/sources.ts @@ -0,0 +1,34 @@ +/** + * The site's content sources — what the sidebar's source selector switches + * between (`components/SourceSidebar.astro`), Fumadocs' "root folders". A + * source owns every route under its `path`, and the sidebar shows only the + * active source's pages. The source at `/` owns whatever no other source + * claims, which is how the LeetCode campaign keeps its routes (`/tree-dfs/…`) + * while a later source mounts beside it. + * + * Adding one: a content folder at the path (`content/system-design/`) with an + * `index.mdx`, so the selector's link is a page, plus a row here. The active + * source is the deepest `path` the current route sits under. + */ +export interface Source { + label: string; + description: string; + /** A Blume built-in icon name. */ + icon: string; + path: string; +} + +export const SOURCES: Source[] = [ + { + label: "LeetCode", + description: "Data structures & algorithms", + icon: "binary", + path: "/", + }, + { + label: "System Design", + description: "Distributed systems interviews", + icon: "network", + path: "/system-design", + }, +];