mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 13:12:44 +00:00
docs(docs): add new problem documentation pages and source selector component
This commit is contained in:
1 parent
598688977a
commit
5627d0ca64
9 files changed
+321
-6
No files matched your search
@@ -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).
|
||||
},
|
||||
});
|
||||
@@ -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",
|
||||
},
|
||||
});
|
||||
@@ -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 `<details>` 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<NavNode, string>;
|
||||
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 : [],
|
||||
);
|
||||
---
|
||||
|
||||
<details class="group relative mb-3" data-blume-dropdown>
|
||||
<summary
|
||||
aria-label={`Content source: ${active.label}`}
|
||||
class="flex w-full cursor-pointer list-none items-center gap-2.5 rounded-xl border border-border bg-muted/50 p-1.5 pe-2.5 text-foreground text-sm transition-colors hover:bg-muted group-open:bg-muted [&::-webkit-details-marker]:hidden"
|
||||
>
|
||||
<span class="flex size-7 shrink-0 items-center justify-center rounded-lg border border-border bg-background">
|
||||
<Icon name={active.icon} size={15} />
|
||||
</span>
|
||||
<span class="min-w-0 flex-1 truncate font-medium">{active.label}</span>
|
||||
<Icon class="shrink-0 text-muted-foreground" name="chevrons-up-down" size={14} />
|
||||
</summary>
|
||||
<div
|
||||
class="absolute inset-x-0 z-50 mt-1.5 rounded-xl border border-border bg-background p-1 shadow-xl"
|
||||
data-blume-dropdown-panel
|
||||
>
|
||||
{
|
||||
SOURCES.map((source) => (
|
||||
<a
|
||||
aria-current={source === active ? "true" : undefined}
|
||||
class="flex items-start gap-2.5 rounded-lg p-2 text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=true]:text-foreground"
|
||||
href={withMountedBase(source.path)}
|
||||
>
|
||||
<Icon class="mt-0.5 shrink-0" name={source.icon} size={16} />
|
||||
<span class="min-w-0 flex-1">
|
||||
<span class="block font-medium">{source.label}</span>
|
||||
<span class="block text-muted-foreground text-xs">{source.description}</span>
|
||||
</span>
|
||||
{source === active && <Icon class="mt-0.5 shrink-0" name="check" size={14} />}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<nav aria-label="Featured" class="mb-4 border-border border-b pb-4">
|
||||
<ul class="m-0 list-none p-0">
|
||||
{
|
||||
PINNED.map((link) => (
|
||||
<li>
|
||||
<a
|
||||
aria-current={currentRoute === link.href ? "page" : undefined}
|
||||
class="flex items-center gap-2 rounded-[0.65rem] px-2.5 py-1.5 text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:bg-muted aria-[current=page]:text-foreground"
|
||||
href={withBase(link.href)}
|
||||
>
|
||||
<Icon class="shrink-0" name={link.icon} size={14} />
|
||||
<span class="flex-1 truncate">{link.label}</span>
|
||||
</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<NavTree {...tree} currentRoute={currentRoute} items={scoped} />
|
||||
|
||||
<script>
|
||||
import { installDropdownDismiss } from "blume/components/dropdown-dismiss.ts";
|
||||
|
||||
installDropdownDismiss();
|
||||
</script>
|
||||
@@ -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)
|
||||
```
|
||||
+46
@@ -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:
|
||||
```
|
||||
@@ -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:
|
||||
```
|
||||
@@ -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
|
||||
|
||||
<Steps>
|
||||
<Step title="Requirements">
|
||||
Pin down the functional requirements (what the system does) and the non-functional ones (latency, availability, consistency, scale) before drawing anything.
|
||||
</Step>
|
||||
<Step title="Estimates">
|
||||
Size the traffic, storage and bandwidth with back-of-the-envelope numbers, so later choices have a reason.
|
||||
</Step>
|
||||
<Step title="API and data model">
|
||||
Define the endpoints and the entities they read and write.
|
||||
</Step>
|
||||
<Step title="High-level design">
|
||||
Draw the request path end to end: clients, load balancers, services, caches, stores and queues.
|
||||
</Step>
|
||||
<Step title="Deep dives">
|
||||
Take the hardest part (a hot key, fan-out, a consistency guarantee) and work through its tradeoffs.
|
||||
</Step>
|
||||
</Steps>
|
||||
@@ -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" },
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
];
|
||||
Reference in new issue
Block a user