leetcode-capture-helper 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.js +92 -0
- package/config.js +25 -0
- package/framing.js +57 -0
- package/host.js +420 -0
- package/install.js +290 -0
- package/package.json +31 -4
- package/runtime/bundle.json +42 -0
- package/runtime/companion/capture-log.js +83 -0
- package/runtime/companion/codex-backend.js +337 -0
- package/runtime/companion/companion.js +2190 -0
- package/runtime/companion/mouse-input.js +154 -0
- package/runtime/companion/package.json +4 -0
- package/runtime/companion/panel-bridge.js +273 -0
- package/runtime/companion/settings-rpc.js +228 -0
- package/runtime/companion/settings.js +464 -0
- package/runtime/companion/terminal-format.js +330 -0
- package/runtime/companion/vault-summary.js +168 -0
- package/runtime/companion/virtual-terminal.js +138 -0
- package/runtime/extension/shared/anthropic-backend.js +193 -0
- package/runtime/extension/shared/catalog.js +415 -0
- package/runtime/extension/shared/code-ledger.js +333 -0
- package/runtime/extension/shared/context-budget.js +259 -0
- package/runtime/extension/shared/context-summary.js +271 -0
- package/runtime/extension/shared/conversation.js +81 -0
- package/runtime/extension/shared/event-hub.js +126 -0
- package/runtime/extension/shared/extension-settings.js +445 -0
- package/runtime/extension/shared/helper-launcher.js +248 -0
- package/runtime/extension/shared/local-backend.js +706 -0
- package/runtime/extension/shared/local-server.js +149 -0
- package/runtime/extension/shared/package.json +4 -0
- package/runtime/extension/shared/practice.js +228 -0
- package/runtime/extension/shared/problem-index.js +4128 -0
- package/runtime/extension/shared/profiles.js +106 -0
- package/runtime/extension/shared/providers.js +58 -0
- package/runtime/extension/shared/reply-guard.js +864 -0
- package/runtime/extension/shared/roadmap.js +1337 -0
- package/runtime/extension/shared/sanitize.js +68 -0
- package/runtime/extension/shared/solved.js +316 -0
- package/runtime/extension/shared/tutor-engine.js +369 -0
- package/runtime/extension/shared/tutor-prompt.js +108 -0
- package/runtime/extension/shared/tutor-service.js +520 -0
- package/runtime/relay-server/package.json +4 -0
- package/runtime/relay-server/panel-broker.js +797 -0
- package/runtime/relay-server/server.js +241 -0
- package/runtime/vault-tool/log-session.js +230 -0
- package/runtime/vault-tool/package.json +4 -0
- package/runtime/vault-tool/vault-notes.js +206 -0
- package/README.md +0 -3
|
@@ -0,0 +1,1337 @@
|
|
|
1
|
+
// The problem lists the Progress tab and the next-problem suggestions follow,
|
|
2
|
+
// plus the pure logic they share. No Node or browser APIs, so the options
|
|
3
|
+
// page, the background worker and the companion can all import it.
|
|
4
|
+
//
|
|
5
|
+
// A list is { id, title, short, kind, topics, edges, subjects }:
|
|
6
|
+
// topics its groups in the publisher's order, each { id, title, problems }
|
|
7
|
+
// where a problem is { slug, title, difficulty, topic } (title and
|
|
8
|
+
// difficulty come from the one shared catalog, shared/catalog.js)
|
|
9
|
+
// edges prerequisite lines [from, to] between topics; only NeetCode 150
|
|
10
|
+
// and NeetCode 250 have them (kind 'graph', one roadmap for both),
|
|
11
|
+
// every other list is drawn as ordered groups (kind 'groups') and
|
|
12
|
+
// its next group is simply the first one not finished
|
|
13
|
+
// subjects only for a list whose own groups are not subjects (Grind 75's
|
|
14
|
+
// weeks): a second grouping of the same problems by subject, each
|
|
15
|
+
// { id, title, problems } with the problems in the list's order;
|
|
16
|
+
// every problem then also carries `subject`. The list's order (and
|
|
17
|
+
// so what comes next) stays the publisher's; subjects are a view.
|
|
18
|
+
// The slug is LeetCode's own (leetcode.com/problems/<slug>/), which is also
|
|
19
|
+
// what the extension reads from the page address, so a problem solved once
|
|
20
|
+
// counts in every list.
|
|
21
|
+
|
|
22
|
+
import { CATALOG } from './catalog.js';
|
|
23
|
+
|
|
24
|
+
const words = (slugs) => slugs.split(/\s+/).filter(Boolean);
|
|
25
|
+
|
|
26
|
+
// Each group: [id, title, slugs], the slugs one per line in the list's order.
|
|
27
|
+
function defineList({ id, title, short, groupNoun, groups, edges = [], subjects = null }) {
|
|
28
|
+
const topics = groups.map(([topicId, topicTitle, slugs]) => ({
|
|
29
|
+
id: topicId,
|
|
30
|
+
title: topicTitle,
|
|
31
|
+
problems: words(slugs).map((slug) => {
|
|
32
|
+
const entry = CATALOG.get(slug);
|
|
33
|
+
if (!entry) throw new Error(`${id}: ${slug} is not in the catalog`);
|
|
34
|
+
return { slug, title: entry.title, difficulty: entry.difficulty, topic: topicId };
|
|
35
|
+
}),
|
|
36
|
+
}));
|
|
37
|
+
const size = topics.reduce((n, t) => n + t.problems.length, 0);
|
|
38
|
+
const list = { id, title, short: short || title, groupNoun, kind: edges.length ? 'graph' : 'groups', size, topics, edges, subjects: null };
|
|
39
|
+
if (subjects) list.subjects = defineSubjects(list, subjects);
|
|
40
|
+
return list;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Every problem of the list in exactly one subject; each subject keeps the
|
|
44
|
+
// list's order.
|
|
45
|
+
function defineSubjects(list, subjects) {
|
|
46
|
+
const problems = list.topics.flatMap((t) => t.problems);
|
|
47
|
+
const where = new Map();
|
|
48
|
+
for (const [subjectId, , slugs] of subjects) {
|
|
49
|
+
for (const slug of words(slugs)) {
|
|
50
|
+
if (where.has(slug)) throw new Error(`${list.id}: ${slug} has two subjects`);
|
|
51
|
+
where.set(slug, subjectId);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const p of problems) {
|
|
55
|
+
if (!where.has(p.slug)) throw new Error(`${list.id}: ${p.slug} has no subject`);
|
|
56
|
+
p.subject = where.get(p.slug);
|
|
57
|
+
}
|
|
58
|
+
if (where.size !== problems.length) throw new Error(`${list.id}: a subject names a problem the list does not have`);
|
|
59
|
+
return subjects.map(([subjectId, subjectTitle]) => ({ id: subjectId, title: subjectTitle, problems: problems.filter((p) => p.subject === subjectId) }));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// NeetCode 150, in NeetCode's order, with its roadmap's prerequisite lines.
|
|
63
|
+
// Membership, topics and the order inside each topic are neetcode.io's own
|
|
64
|
+
// list data (https://neetcode.io/practice/practice/neetcode150, the problem
|
|
65
|
+
// objects in its main bundle, fetched 2026-11-04: e2e/neetcode-lists.txt,
|
|
66
|
+
// which roadmap.test.mjs compares). The older copy in the neetcode-gh/leetcode
|
|
67
|
+
// repository (.problemSiteData.json) still has Generate Parentheses under
|
|
68
|
+
// Stack; the site now lists it under Backtracking.
|
|
69
|
+
// The roadmap's own prerequisite lines: [from, to].
|
|
70
|
+
const EDGES = [
|
|
71
|
+
['arrays-hashing', 'two-pointers'],
|
|
72
|
+
['arrays-hashing', 'stack'],
|
|
73
|
+
['two-pointers', 'binary-search'],
|
|
74
|
+
['two-pointers', 'sliding-window'],
|
|
75
|
+
['two-pointers', 'linked-list'],
|
|
76
|
+
['binary-search', 'trees'],
|
|
77
|
+
['linked-list', 'trees'],
|
|
78
|
+
['trees', 'tries'],
|
|
79
|
+
['trees', 'heap'],
|
|
80
|
+
['trees', 'backtracking'],
|
|
81
|
+
['backtracking', 'graphs'],
|
|
82
|
+
['backtracking', 'dp-1d'],
|
|
83
|
+
['heap', 'intervals'],
|
|
84
|
+
['heap', 'greedy'],
|
|
85
|
+
['heap', 'advanced-graphs'],
|
|
86
|
+
['graphs', 'advanced-graphs'],
|
|
87
|
+
['graphs', 'dp-2d'],
|
|
88
|
+
['dp-1d', 'dp-2d'],
|
|
89
|
+
['dp-1d', 'bit-manipulation'],
|
|
90
|
+
['dp-2d', 'math-geometry'],
|
|
91
|
+
['bit-manipulation', 'math-geometry'],
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
export const NEETCODE_150 = defineList({
|
|
95
|
+
id: 'neetcode-150',
|
|
96
|
+
title: 'NeetCode 150',
|
|
97
|
+
groupNoun: 'topic',
|
|
98
|
+
edges: EDGES,
|
|
99
|
+
groups: [
|
|
100
|
+
['arrays-hashing', 'Arrays & Hashing', `
|
|
101
|
+
contains-duplicate
|
|
102
|
+
valid-anagram
|
|
103
|
+
two-sum
|
|
104
|
+
group-anagrams
|
|
105
|
+
top-k-frequent-elements
|
|
106
|
+
encode-and-decode-strings
|
|
107
|
+
product-of-array-except-self
|
|
108
|
+
valid-sudoku
|
|
109
|
+
longest-consecutive-sequence`],
|
|
110
|
+
['two-pointers', 'Two Pointers', `
|
|
111
|
+
valid-palindrome
|
|
112
|
+
two-sum-ii-input-array-is-sorted
|
|
113
|
+
3sum
|
|
114
|
+
container-with-most-water
|
|
115
|
+
trapping-rain-water`],
|
|
116
|
+
['sliding-window', 'Sliding Window', `
|
|
117
|
+
best-time-to-buy-and-sell-stock
|
|
118
|
+
longest-substring-without-repeating-characters
|
|
119
|
+
longest-repeating-character-replacement
|
|
120
|
+
permutation-in-string
|
|
121
|
+
minimum-window-substring
|
|
122
|
+
sliding-window-maximum`],
|
|
123
|
+
['stack', 'Stack', `
|
|
124
|
+
valid-parentheses
|
|
125
|
+
min-stack
|
|
126
|
+
evaluate-reverse-polish-notation
|
|
127
|
+
daily-temperatures
|
|
128
|
+
car-fleet
|
|
129
|
+
largest-rectangle-in-histogram`],
|
|
130
|
+
['binary-search', 'Binary Search', `
|
|
131
|
+
binary-search
|
|
132
|
+
search-a-2d-matrix
|
|
133
|
+
koko-eating-bananas
|
|
134
|
+
find-minimum-in-rotated-sorted-array
|
|
135
|
+
search-in-rotated-sorted-array
|
|
136
|
+
time-based-key-value-store
|
|
137
|
+
median-of-two-sorted-arrays`],
|
|
138
|
+
['linked-list', 'Linked List', `
|
|
139
|
+
reverse-linked-list
|
|
140
|
+
merge-two-sorted-lists
|
|
141
|
+
linked-list-cycle
|
|
142
|
+
reorder-list
|
|
143
|
+
remove-nth-node-from-end-of-list
|
|
144
|
+
copy-list-with-random-pointer
|
|
145
|
+
add-two-numbers
|
|
146
|
+
find-the-duplicate-number
|
|
147
|
+
lru-cache
|
|
148
|
+
merge-k-sorted-lists
|
|
149
|
+
reverse-nodes-in-k-group`],
|
|
150
|
+
['trees', 'Trees', `
|
|
151
|
+
invert-binary-tree
|
|
152
|
+
maximum-depth-of-binary-tree
|
|
153
|
+
diameter-of-binary-tree
|
|
154
|
+
balanced-binary-tree
|
|
155
|
+
same-tree
|
|
156
|
+
subtree-of-another-tree
|
|
157
|
+
lowest-common-ancestor-of-a-binary-search-tree
|
|
158
|
+
binary-tree-level-order-traversal
|
|
159
|
+
binary-tree-right-side-view
|
|
160
|
+
count-good-nodes-in-binary-tree
|
|
161
|
+
validate-binary-search-tree
|
|
162
|
+
kth-smallest-element-in-a-bst
|
|
163
|
+
construct-binary-tree-from-preorder-and-inorder-traversal
|
|
164
|
+
binary-tree-maximum-path-sum
|
|
165
|
+
serialize-and-deserialize-binary-tree`],
|
|
166
|
+
['heap', 'Heap / Priority Queue', `
|
|
167
|
+
kth-largest-element-in-a-stream
|
|
168
|
+
last-stone-weight
|
|
169
|
+
k-closest-points-to-origin
|
|
170
|
+
kth-largest-element-in-an-array
|
|
171
|
+
task-scheduler
|
|
172
|
+
design-twitter
|
|
173
|
+
find-median-from-data-stream`],
|
|
174
|
+
['backtracking', 'Backtracking', `
|
|
175
|
+
subsets
|
|
176
|
+
combination-sum
|
|
177
|
+
combination-sum-ii
|
|
178
|
+
permutations
|
|
179
|
+
subsets-ii
|
|
180
|
+
generate-parentheses
|
|
181
|
+
word-search
|
|
182
|
+
palindrome-partitioning
|
|
183
|
+
letter-combinations-of-a-phone-number
|
|
184
|
+
n-queens`],
|
|
185
|
+
['tries', 'Tries', `
|
|
186
|
+
implement-trie-prefix-tree
|
|
187
|
+
design-add-and-search-words-data-structure
|
|
188
|
+
word-search-ii`],
|
|
189
|
+
['graphs', 'Graphs', `
|
|
190
|
+
number-of-islands
|
|
191
|
+
max-area-of-island
|
|
192
|
+
clone-graph
|
|
193
|
+
walls-and-gates
|
|
194
|
+
rotting-oranges
|
|
195
|
+
pacific-atlantic-water-flow
|
|
196
|
+
surrounded-regions
|
|
197
|
+
course-schedule
|
|
198
|
+
course-schedule-ii
|
|
199
|
+
graph-valid-tree
|
|
200
|
+
number-of-connected-components-in-an-undirected-graph
|
|
201
|
+
redundant-connection
|
|
202
|
+
word-ladder`],
|
|
203
|
+
['advanced-graphs', 'Advanced Graphs', `
|
|
204
|
+
network-delay-time
|
|
205
|
+
reconstruct-itinerary
|
|
206
|
+
min-cost-to-connect-all-points
|
|
207
|
+
swim-in-rising-water
|
|
208
|
+
alien-dictionary
|
|
209
|
+
cheapest-flights-within-k-stops`],
|
|
210
|
+
['dp-1d', '1-D Dynamic Programming', `
|
|
211
|
+
climbing-stairs
|
|
212
|
+
min-cost-climbing-stairs
|
|
213
|
+
house-robber
|
|
214
|
+
house-robber-ii
|
|
215
|
+
longest-palindromic-substring
|
|
216
|
+
palindromic-substrings
|
|
217
|
+
decode-ways
|
|
218
|
+
coin-change
|
|
219
|
+
maximum-product-subarray
|
|
220
|
+
word-break
|
|
221
|
+
longest-increasing-subsequence
|
|
222
|
+
partition-equal-subset-sum`],
|
|
223
|
+
['dp-2d', '2-D Dynamic Programming', `
|
|
224
|
+
unique-paths
|
|
225
|
+
longest-common-subsequence
|
|
226
|
+
best-time-to-buy-and-sell-stock-with-cooldown
|
|
227
|
+
coin-change-ii
|
|
228
|
+
target-sum
|
|
229
|
+
interleaving-string
|
|
230
|
+
longest-increasing-path-in-a-matrix
|
|
231
|
+
distinct-subsequences
|
|
232
|
+
edit-distance
|
|
233
|
+
burst-balloons
|
|
234
|
+
regular-expression-matching`],
|
|
235
|
+
['greedy', 'Greedy', `
|
|
236
|
+
maximum-subarray
|
|
237
|
+
jump-game
|
|
238
|
+
jump-game-ii
|
|
239
|
+
gas-station
|
|
240
|
+
hand-of-straights
|
|
241
|
+
merge-triplets-to-form-target-triplet
|
|
242
|
+
partition-labels
|
|
243
|
+
valid-parenthesis-string`],
|
|
244
|
+
['intervals', 'Intervals', `
|
|
245
|
+
insert-interval
|
|
246
|
+
merge-intervals
|
|
247
|
+
non-overlapping-intervals
|
|
248
|
+
meeting-rooms
|
|
249
|
+
meeting-rooms-ii
|
|
250
|
+
minimum-interval-to-include-each-query`],
|
|
251
|
+
['bit-manipulation', 'Bit Manipulation', `
|
|
252
|
+
single-number
|
|
253
|
+
number-of-1-bits
|
|
254
|
+
counting-bits
|
|
255
|
+
reverse-bits
|
|
256
|
+
missing-number
|
|
257
|
+
sum-of-two-integers
|
|
258
|
+
reverse-integer`],
|
|
259
|
+
['math-geometry', 'Math & Geometry', `
|
|
260
|
+
rotate-image
|
|
261
|
+
spiral-matrix
|
|
262
|
+
set-matrix-zeroes
|
|
263
|
+
happy-number
|
|
264
|
+
plus-one
|
|
265
|
+
powx-n
|
|
266
|
+
multiply-strings
|
|
267
|
+
detect-squares`],
|
|
268
|
+
],
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// NeetCode 250: NeetCode 150 plus 100 more, on the same roadmap (the same
|
|
272
|
+
// topics and prerequisite lines). Membership and the order inside each topic
|
|
273
|
+
// are neetcode.io's own list data (https://neetcode.io/practice/practice/neetcode250,
|
|
274
|
+
// the problem objects in its main bundle, fetched 2026-11-04:
|
|
275
|
+
// e2e/neetcode-lists.txt, which roadmap.test.mjs compares). The topics keep
|
|
276
|
+
// NeetCode 150's order (neetcode.io puts Math & Geometry before Bit
|
|
277
|
+
// Manipulation here, but the roadmap leads from Bit Manipulation to it).
|
|
278
|
+
export const NEETCODE_250 = defineList({
|
|
279
|
+
id: 'neetcode-250',
|
|
280
|
+
title: 'NeetCode 250',
|
|
281
|
+
groupNoun: 'topic',
|
|
282
|
+
edges: EDGES,
|
|
283
|
+
groups: [
|
|
284
|
+
['arrays-hashing', 'Arrays & Hashing', `
|
|
285
|
+
concatenation-of-array
|
|
286
|
+
contains-duplicate
|
|
287
|
+
valid-anagram
|
|
288
|
+
two-sum
|
|
289
|
+
longest-common-prefix
|
|
290
|
+
group-anagrams
|
|
291
|
+
remove-element
|
|
292
|
+
majority-element
|
|
293
|
+
design-hashset
|
|
294
|
+
design-hashmap
|
|
295
|
+
sort-an-array
|
|
296
|
+
sort-colors
|
|
297
|
+
top-k-frequent-elements
|
|
298
|
+
encode-and-decode-strings
|
|
299
|
+
range-sum-query-2d-immutable
|
|
300
|
+
product-of-array-except-self
|
|
301
|
+
valid-sudoku
|
|
302
|
+
longest-consecutive-sequence
|
|
303
|
+
best-time-to-buy-and-sell-stock-ii
|
|
304
|
+
majority-element-ii
|
|
305
|
+
subarray-sum-equals-k
|
|
306
|
+
first-missing-positive`],
|
|
307
|
+
['two-pointers', 'Two Pointers', `
|
|
308
|
+
reverse-string
|
|
309
|
+
valid-palindrome
|
|
310
|
+
valid-palindrome-ii
|
|
311
|
+
merge-strings-alternately
|
|
312
|
+
merge-sorted-array
|
|
313
|
+
remove-duplicates-from-sorted-array
|
|
314
|
+
two-sum-ii-input-array-is-sorted
|
|
315
|
+
3sum
|
|
316
|
+
4sum
|
|
317
|
+
rotate-array
|
|
318
|
+
container-with-most-water
|
|
319
|
+
boats-to-save-people
|
|
320
|
+
trapping-rain-water`],
|
|
321
|
+
['sliding-window', 'Sliding Window', `
|
|
322
|
+
contains-duplicate-ii
|
|
323
|
+
best-time-to-buy-and-sell-stock
|
|
324
|
+
longest-substring-without-repeating-characters
|
|
325
|
+
longest-repeating-character-replacement
|
|
326
|
+
permutation-in-string
|
|
327
|
+
minimum-size-subarray-sum
|
|
328
|
+
find-k-closest-elements
|
|
329
|
+
minimum-window-substring
|
|
330
|
+
sliding-window-maximum`],
|
|
331
|
+
['stack', 'Stack', `
|
|
332
|
+
baseball-game
|
|
333
|
+
valid-parentheses
|
|
334
|
+
implement-stack-using-queues
|
|
335
|
+
implement-queue-using-stacks
|
|
336
|
+
min-stack
|
|
337
|
+
evaluate-reverse-polish-notation
|
|
338
|
+
asteroid-collision
|
|
339
|
+
daily-temperatures
|
|
340
|
+
online-stock-span
|
|
341
|
+
car-fleet
|
|
342
|
+
simplify-path
|
|
343
|
+
decode-string
|
|
344
|
+
maximum-frequency-stack
|
|
345
|
+
largest-rectangle-in-histogram`],
|
|
346
|
+
['binary-search', 'Binary Search', `
|
|
347
|
+
binary-search
|
|
348
|
+
search-insert-position
|
|
349
|
+
guess-number-higher-or-lower
|
|
350
|
+
sqrtx
|
|
351
|
+
search-a-2d-matrix
|
|
352
|
+
koko-eating-bananas
|
|
353
|
+
capacity-to-ship-packages-within-d-days
|
|
354
|
+
find-minimum-in-rotated-sorted-array
|
|
355
|
+
search-in-rotated-sorted-array
|
|
356
|
+
search-in-rotated-sorted-array-ii
|
|
357
|
+
time-based-key-value-store
|
|
358
|
+
split-array-largest-sum
|
|
359
|
+
median-of-two-sorted-arrays
|
|
360
|
+
find-in-mountain-array`],
|
|
361
|
+
['linked-list', 'Linked List', `
|
|
362
|
+
reverse-linked-list
|
|
363
|
+
merge-two-sorted-lists
|
|
364
|
+
linked-list-cycle
|
|
365
|
+
reorder-list
|
|
366
|
+
remove-nth-node-from-end-of-list
|
|
367
|
+
copy-list-with-random-pointer
|
|
368
|
+
add-two-numbers
|
|
369
|
+
find-the-duplicate-number
|
|
370
|
+
reverse-linked-list-ii
|
|
371
|
+
design-circular-queue
|
|
372
|
+
lru-cache
|
|
373
|
+
lfu-cache
|
|
374
|
+
merge-k-sorted-lists
|
|
375
|
+
reverse-nodes-in-k-group`],
|
|
376
|
+
['trees', 'Trees', `
|
|
377
|
+
binary-tree-inorder-traversal
|
|
378
|
+
binary-tree-preorder-traversal
|
|
379
|
+
binary-tree-postorder-traversal
|
|
380
|
+
invert-binary-tree
|
|
381
|
+
maximum-depth-of-binary-tree
|
|
382
|
+
diameter-of-binary-tree
|
|
383
|
+
balanced-binary-tree
|
|
384
|
+
same-tree
|
|
385
|
+
subtree-of-another-tree
|
|
386
|
+
lowest-common-ancestor-of-a-binary-search-tree
|
|
387
|
+
insert-into-a-binary-search-tree
|
|
388
|
+
delete-node-in-a-bst
|
|
389
|
+
binary-tree-level-order-traversal
|
|
390
|
+
binary-tree-right-side-view
|
|
391
|
+
construct-quad-tree
|
|
392
|
+
count-good-nodes-in-binary-tree
|
|
393
|
+
validate-binary-search-tree
|
|
394
|
+
kth-smallest-element-in-a-bst
|
|
395
|
+
construct-binary-tree-from-preorder-and-inorder-traversal
|
|
396
|
+
house-robber-iii
|
|
397
|
+
delete-leaves-with-a-given-value
|
|
398
|
+
binary-tree-maximum-path-sum
|
|
399
|
+
serialize-and-deserialize-binary-tree`],
|
|
400
|
+
['heap', 'Heap / Priority Queue', `
|
|
401
|
+
kth-largest-element-in-a-stream
|
|
402
|
+
last-stone-weight
|
|
403
|
+
k-closest-points-to-origin
|
|
404
|
+
kth-largest-element-in-an-array
|
|
405
|
+
task-scheduler
|
|
406
|
+
design-twitter
|
|
407
|
+
single-threaded-cpu
|
|
408
|
+
reorganize-string
|
|
409
|
+
longest-happy-string
|
|
410
|
+
car-pooling
|
|
411
|
+
find-median-from-data-stream
|
|
412
|
+
ipo`],
|
|
413
|
+
['backtracking', 'Backtracking', `
|
|
414
|
+
sum-of-all-subset-xor-totals
|
|
415
|
+
subsets
|
|
416
|
+
combination-sum
|
|
417
|
+
combination-sum-ii
|
|
418
|
+
combinations
|
|
419
|
+
permutations
|
|
420
|
+
subsets-ii
|
|
421
|
+
permutations-ii
|
|
422
|
+
generate-parentheses
|
|
423
|
+
word-search
|
|
424
|
+
palindrome-partitioning
|
|
425
|
+
letter-combinations-of-a-phone-number
|
|
426
|
+
matchsticks-to-square
|
|
427
|
+
partition-to-k-equal-sum-subsets
|
|
428
|
+
n-queens
|
|
429
|
+
n-queens-ii
|
|
430
|
+
word-break-ii`],
|
|
431
|
+
['tries', 'Tries', `
|
|
432
|
+
implement-trie-prefix-tree
|
|
433
|
+
design-add-and-search-words-data-structure
|
|
434
|
+
extra-characters-in-a-string
|
|
435
|
+
word-search-ii`],
|
|
436
|
+
['graphs', 'Graphs', `
|
|
437
|
+
island-perimeter
|
|
438
|
+
verifying-an-alien-dictionary
|
|
439
|
+
find-the-town-judge
|
|
440
|
+
number-of-islands
|
|
441
|
+
max-area-of-island
|
|
442
|
+
clone-graph
|
|
443
|
+
walls-and-gates
|
|
444
|
+
rotting-oranges
|
|
445
|
+
pacific-atlantic-water-flow
|
|
446
|
+
surrounded-regions
|
|
447
|
+
open-the-lock
|
|
448
|
+
course-schedule
|
|
449
|
+
course-schedule-ii
|
|
450
|
+
graph-valid-tree
|
|
451
|
+
course-schedule-iv
|
|
452
|
+
number-of-connected-components-in-an-undirected-graph
|
|
453
|
+
redundant-connection
|
|
454
|
+
accounts-merge
|
|
455
|
+
evaluate-division
|
|
456
|
+
minimum-height-trees
|
|
457
|
+
word-ladder`],
|
|
458
|
+
['advanced-graphs', 'Advanced Graphs', `
|
|
459
|
+
path-with-minimum-effort
|
|
460
|
+
network-delay-time
|
|
461
|
+
reconstruct-itinerary
|
|
462
|
+
min-cost-to-connect-all-points
|
|
463
|
+
swim-in-rising-water
|
|
464
|
+
alien-dictionary
|
|
465
|
+
cheapest-flights-within-k-stops
|
|
466
|
+
find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree
|
|
467
|
+
build-a-matrix-with-conditions
|
|
468
|
+
greatest-common-divisor-traversal`],
|
|
469
|
+
['dp-1d', '1-D Dynamic Programming', `
|
|
470
|
+
climbing-stairs
|
|
471
|
+
min-cost-climbing-stairs
|
|
472
|
+
n-th-tribonacci-number
|
|
473
|
+
house-robber
|
|
474
|
+
house-robber-ii
|
|
475
|
+
longest-palindromic-substring
|
|
476
|
+
palindromic-substrings
|
|
477
|
+
decode-ways
|
|
478
|
+
coin-change
|
|
479
|
+
maximum-product-subarray
|
|
480
|
+
word-break
|
|
481
|
+
longest-increasing-subsequence
|
|
482
|
+
partition-equal-subset-sum
|
|
483
|
+
combination-sum-iv
|
|
484
|
+
perfect-squares
|
|
485
|
+
integer-break
|
|
486
|
+
stone-game-iii`],
|
|
487
|
+
['dp-2d', '2-D Dynamic Programming', `
|
|
488
|
+
unique-paths
|
|
489
|
+
unique-paths-ii
|
|
490
|
+
minimum-path-sum
|
|
491
|
+
longest-common-subsequence
|
|
492
|
+
last-stone-weight-ii
|
|
493
|
+
best-time-to-buy-and-sell-stock-with-cooldown
|
|
494
|
+
coin-change-ii
|
|
495
|
+
target-sum
|
|
496
|
+
interleaving-string
|
|
497
|
+
stone-game
|
|
498
|
+
stone-game-ii
|
|
499
|
+
longest-increasing-path-in-a-matrix
|
|
500
|
+
distinct-subsequences
|
|
501
|
+
edit-distance
|
|
502
|
+
burst-balloons
|
|
503
|
+
regular-expression-matching`],
|
|
504
|
+
['greedy', 'Greedy', `
|
|
505
|
+
lemonade-change
|
|
506
|
+
maximum-subarray
|
|
507
|
+
maximum-sum-circular-subarray
|
|
508
|
+
longest-turbulent-subarray
|
|
509
|
+
jump-game
|
|
510
|
+
jump-game-ii
|
|
511
|
+
jump-game-vii
|
|
512
|
+
gas-station
|
|
513
|
+
hand-of-straights
|
|
514
|
+
dota2-senate
|
|
515
|
+
merge-triplets-to-form-target-triplet
|
|
516
|
+
partition-labels
|
|
517
|
+
valid-parenthesis-string
|
|
518
|
+
candy`],
|
|
519
|
+
['intervals', 'Intervals', `
|
|
520
|
+
insert-interval
|
|
521
|
+
merge-intervals
|
|
522
|
+
non-overlapping-intervals
|
|
523
|
+
meeting-rooms
|
|
524
|
+
meeting-rooms-ii
|
|
525
|
+
meeting-rooms-iii
|
|
526
|
+
minimum-interval-to-include-each-query`],
|
|
527
|
+
['bit-manipulation', 'Bit Manipulation', `
|
|
528
|
+
single-number
|
|
529
|
+
number-of-1-bits
|
|
530
|
+
counting-bits
|
|
531
|
+
add-binary
|
|
532
|
+
reverse-bits
|
|
533
|
+
missing-number
|
|
534
|
+
sum-of-two-integers
|
|
535
|
+
reverse-integer
|
|
536
|
+
bitwise-and-of-numbers-range
|
|
537
|
+
minimum-array-end`],
|
|
538
|
+
['math-geometry', 'Math & Geometry', `
|
|
539
|
+
excel-sheet-column-title
|
|
540
|
+
greatest-common-divisor-of-strings
|
|
541
|
+
insert-greatest-common-divisors-in-linked-list
|
|
542
|
+
transpose-matrix
|
|
543
|
+
rotate-image
|
|
544
|
+
spiral-matrix
|
|
545
|
+
set-matrix-zeroes
|
|
546
|
+
happy-number
|
|
547
|
+
plus-one
|
|
548
|
+
roman-to-integer
|
|
549
|
+
powx-n
|
|
550
|
+
multiply-strings
|
|
551
|
+
detect-squares`],
|
|
552
|
+
],
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
// The original Blind 75, exactly as the 2018 post lists it
|
|
556
|
+
// (https://www.teamblind.com/post/New-Year-Gift---Curated-List-of-Top-75-LeetCode-Questions-to-Save-Your-Time-OaM1orEU,
|
|
557
|
+
// saved as e2e/blind-75.txt by scripts/list-sources.mjs and compared by
|
|
558
|
+
// roadmap.test.mjs): its categories, their order and the order inside each.
|
|
559
|
+
// Merge k Sorted Lists is listed under both Linked List and Heap there; it is
|
|
560
|
+
// kept once, under Linked List, so the list has 75 distinct problems.
|
|
561
|
+
// neetcode.io's Blind 75 (its blind75 flag) has the same problems but one:
|
|
562
|
+
// the post's "Combination Sum" links to Combination Sum IV, which neetcode.io
|
|
563
|
+
// replaces with Combination Sum. The post's own link is kept here.
|
|
564
|
+
export const BLIND_75 = defineList({
|
|
565
|
+
id: 'blind-75',
|
|
566
|
+
title: 'Blind 75',
|
|
567
|
+
groupNoun: 'category',
|
|
568
|
+
groups: [
|
|
569
|
+
['array', 'Array', `
|
|
570
|
+
two-sum
|
|
571
|
+
best-time-to-buy-and-sell-stock
|
|
572
|
+
contains-duplicate
|
|
573
|
+
product-of-array-except-self
|
|
574
|
+
maximum-subarray
|
|
575
|
+
maximum-product-subarray
|
|
576
|
+
find-minimum-in-rotated-sorted-array
|
|
577
|
+
search-in-rotated-sorted-array
|
|
578
|
+
3sum
|
|
579
|
+
container-with-most-water`],
|
|
580
|
+
['binary', 'Binary', `
|
|
581
|
+
sum-of-two-integers
|
|
582
|
+
number-of-1-bits
|
|
583
|
+
counting-bits
|
|
584
|
+
missing-number
|
|
585
|
+
reverse-bits`],
|
|
586
|
+
['dynamic-programming', 'Dynamic Programming', `
|
|
587
|
+
climbing-stairs
|
|
588
|
+
coin-change
|
|
589
|
+
longest-increasing-subsequence
|
|
590
|
+
longest-common-subsequence
|
|
591
|
+
word-break
|
|
592
|
+
combination-sum-iv
|
|
593
|
+
house-robber
|
|
594
|
+
house-robber-ii
|
|
595
|
+
decode-ways
|
|
596
|
+
unique-paths
|
|
597
|
+
jump-game`],
|
|
598
|
+
['graph', 'Graph', `
|
|
599
|
+
clone-graph
|
|
600
|
+
course-schedule
|
|
601
|
+
pacific-atlantic-water-flow
|
|
602
|
+
number-of-islands
|
|
603
|
+
longest-consecutive-sequence
|
|
604
|
+
alien-dictionary
|
|
605
|
+
graph-valid-tree
|
|
606
|
+
number-of-connected-components-in-an-undirected-graph`],
|
|
607
|
+
['interval', 'Interval', `
|
|
608
|
+
insert-interval
|
|
609
|
+
merge-intervals
|
|
610
|
+
non-overlapping-intervals
|
|
611
|
+
meeting-rooms
|
|
612
|
+
meeting-rooms-ii`],
|
|
613
|
+
['linked-list', 'Linked List', `
|
|
614
|
+
reverse-linked-list
|
|
615
|
+
linked-list-cycle
|
|
616
|
+
merge-two-sorted-lists
|
|
617
|
+
merge-k-sorted-lists
|
|
618
|
+
remove-nth-node-from-end-of-list
|
|
619
|
+
reorder-list`],
|
|
620
|
+
['matrix', 'Matrix', `
|
|
621
|
+
set-matrix-zeroes
|
|
622
|
+
spiral-matrix
|
|
623
|
+
rotate-image
|
|
624
|
+
word-search`],
|
|
625
|
+
['string', 'String', `
|
|
626
|
+
longest-substring-without-repeating-characters
|
|
627
|
+
longest-repeating-character-replacement
|
|
628
|
+
minimum-window-substring
|
|
629
|
+
valid-anagram
|
|
630
|
+
group-anagrams
|
|
631
|
+
valid-parentheses
|
|
632
|
+
valid-palindrome
|
|
633
|
+
longest-palindromic-substring
|
|
634
|
+
palindromic-substrings
|
|
635
|
+
encode-and-decode-strings`],
|
|
636
|
+
['tree', 'Tree', `
|
|
637
|
+
maximum-depth-of-binary-tree
|
|
638
|
+
same-tree
|
|
639
|
+
invert-binary-tree
|
|
640
|
+
binary-tree-maximum-path-sum
|
|
641
|
+
binary-tree-level-order-traversal
|
|
642
|
+
serialize-and-deserialize-binary-tree
|
|
643
|
+
subtree-of-another-tree
|
|
644
|
+
construct-binary-tree-from-preorder-and-inorder-traversal
|
|
645
|
+
validate-binary-search-tree
|
|
646
|
+
kth-smallest-element-in-a-bst
|
|
647
|
+
lowest-common-ancestor-of-a-binary-search-tree
|
|
648
|
+
implement-trie-prefix-tree
|
|
649
|
+
design-add-and-search-words-data-structure
|
|
650
|
+
word-search-ii`],
|
|
651
|
+
['heap', 'Heap', `
|
|
652
|
+
top-k-frequent-elements
|
|
653
|
+
find-median-from-data-stream`],
|
|
654
|
+
],
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
// Grind 75 (Yangshun Tay, https://www.techinterviewhandbook.org/grind75) as
|
|
658
|
+
// the site shows it at its defaults: 8 weeks at 8 hours a week, ordered by
|
|
659
|
+
// difficulty, grouped by weeks. The site computes that from its own data (169
|
|
660
|
+
// questions): it takes questions by priority while 1.96 minutes per minute of
|
|
661
|
+
// each one's duration fit in 60 * 8 * 8, which gives exactly these 75, orders
|
|
662
|
+
// them Easy, Medium, Hard (keeping priority order inside each), and starts a
|
|
663
|
+
// new week once the next one would pass 60 * 8. Other settings change both
|
|
664
|
+
// the set and the weeks (12 weeks gives 111 questions), so this list is only
|
|
665
|
+
// the default. e2e/grind-75.txt is that result, written by
|
|
666
|
+
// scripts/list-sources.mjs, and roadmap.test.mjs compares it. The site still
|
|
667
|
+
// grades Lowest Common Ancestor of a Binary Search Tree Easy; LeetCode now
|
|
668
|
+
// says Medium, and the catalog keeps LeetCode's grade.
|
|
669
|
+
export const GRIND_75 = defineList({
|
|
670
|
+
id: 'grind-75',
|
|
671
|
+
title: 'Grind 75',
|
|
672
|
+
groupNoun: 'week',
|
|
673
|
+
groups: [
|
|
674
|
+
['week-1', 'Week 1', `
|
|
675
|
+
two-sum
|
|
676
|
+
valid-parentheses
|
|
677
|
+
merge-two-sorted-lists
|
|
678
|
+
best-time-to-buy-and-sell-stock
|
|
679
|
+
valid-palindrome
|
|
680
|
+
invert-binary-tree
|
|
681
|
+
valid-anagram
|
|
682
|
+
binary-search
|
|
683
|
+
flood-fill
|
|
684
|
+
lowest-common-ancestor-of-a-binary-search-tree
|
|
685
|
+
balanced-binary-tree
|
|
686
|
+
linked-list-cycle
|
|
687
|
+
implement-queue-using-stacks`],
|
|
688
|
+
['week-2', 'Week 2', `
|
|
689
|
+
first-bad-version
|
|
690
|
+
ransom-note
|
|
691
|
+
climbing-stairs
|
|
692
|
+
longest-palindrome
|
|
693
|
+
reverse-linked-list
|
|
694
|
+
majority-element
|
|
695
|
+
add-binary
|
|
696
|
+
diameter-of-binary-tree
|
|
697
|
+
middle-of-the-linked-list
|
|
698
|
+
maximum-depth-of-binary-tree
|
|
699
|
+
contains-duplicate
|
|
700
|
+
maximum-subarray`],
|
|
701
|
+
['week-3', 'Week 3', `
|
|
702
|
+
insert-interval
|
|
703
|
+
01-matrix
|
|
704
|
+
k-closest-points-to-origin
|
|
705
|
+
longest-substring-without-repeating-characters
|
|
706
|
+
3sum
|
|
707
|
+
binary-tree-level-order-traversal
|
|
708
|
+
clone-graph
|
|
709
|
+
evaluate-reverse-polish-notation`],
|
|
710
|
+
['week-4', 'Week 4', `
|
|
711
|
+
course-schedule
|
|
712
|
+
implement-trie-prefix-tree
|
|
713
|
+
coin-change
|
|
714
|
+
product-of-array-except-self
|
|
715
|
+
min-stack
|
|
716
|
+
validate-binary-search-tree
|
|
717
|
+
number-of-islands
|
|
718
|
+
rotting-oranges`],
|
|
719
|
+
['week-5', 'Week 5', `
|
|
720
|
+
search-in-rotated-sorted-array
|
|
721
|
+
combination-sum
|
|
722
|
+
permutations
|
|
723
|
+
merge-intervals
|
|
724
|
+
lowest-common-ancestor-of-a-binary-tree
|
|
725
|
+
time-based-key-value-store
|
|
726
|
+
accounts-merge
|
|
727
|
+
sort-colors`],
|
|
728
|
+
['week-6', 'Week 6', `
|
|
729
|
+
word-break
|
|
730
|
+
partition-equal-subset-sum
|
|
731
|
+
string-to-integer-atoi
|
|
732
|
+
spiral-matrix
|
|
733
|
+
subsets
|
|
734
|
+
binary-tree-right-side-view
|
|
735
|
+
longest-palindromic-substring
|
|
736
|
+
unique-paths
|
|
737
|
+
construct-binary-tree-from-preorder-and-inorder-traversal`],
|
|
738
|
+
['week-7', 'Week 7', `
|
|
739
|
+
container-with-most-water
|
|
740
|
+
letter-combinations-of-a-phone-number
|
|
741
|
+
word-search
|
|
742
|
+
find-all-anagrams-in-a-string
|
|
743
|
+
minimum-height-trees
|
|
744
|
+
task-scheduler
|
|
745
|
+
lru-cache`],
|
|
746
|
+
['week-8', 'Week 8', `
|
|
747
|
+
kth-smallest-element-in-a-bst
|
|
748
|
+
minimum-window-substring
|
|
749
|
+
serialize-and-deserialize-binary-tree
|
|
750
|
+
trapping-rain-water
|
|
751
|
+
find-median-from-data-stream
|
|
752
|
+
word-ladder
|
|
753
|
+
basic-calculator
|
|
754
|
+
maximum-profit-in-job-scheduling
|
|
755
|
+
merge-k-sorted-lists
|
|
756
|
+
largest-rectangle-in-histogram`],
|
|
757
|
+
],
|
|
758
|
+
// Grind 75 groups by week only, so each problem also gets one subject, in
|
|
759
|
+
// NeetCode's topic names and order: the topic neetcode.io itself gives the
|
|
760
|
+
// problem (its NeetCode 150 topic, else its NeetCode 250 topic, else the
|
|
761
|
+
// topic in neetcode.io's full catalog; e2e/neetcode-lists.txt has all three,
|
|
762
|
+
// and roadmap.test.mjs checks the rule). Four are not on neetcode.io at all
|
|
763
|
+
// and follow their LeetCode tags (shared/problem-index.js): 01 Matrix (Array,
|
|
764
|
+
// Dynamic Programming, Matrix, Breadth-First Search) is Graphs, a grid BFS
|
|
765
|
+
// like Rotting Oranges; First Bad Version (Binary Search, Interactive) is
|
|
766
|
+
// Binary Search; String to Integer (atoi) (String only) is Arrays & Hashing,
|
|
767
|
+
// where NeetCode puts plain string problems; Basic Calculator (String, Math,
|
|
768
|
+
// Stack, Recursion) is Stack.
|
|
769
|
+
subjects: [
|
|
770
|
+
['arrays-hashing', 'Arrays & Hashing', `
|
|
771
|
+
two-sum
|
|
772
|
+
valid-anagram
|
|
773
|
+
ransom-note
|
|
774
|
+
longest-palindrome
|
|
775
|
+
majority-element
|
|
776
|
+
contains-duplicate
|
|
777
|
+
product-of-array-except-self
|
|
778
|
+
sort-colors
|
|
779
|
+
string-to-integer-atoi
|
|
780
|
+
find-all-anagrams-in-a-string`],
|
|
781
|
+
['two-pointers', 'Two Pointers', `
|
|
782
|
+
valid-palindrome
|
|
783
|
+
3sum
|
|
784
|
+
container-with-most-water
|
|
785
|
+
trapping-rain-water`],
|
|
786
|
+
['sliding-window', 'Sliding Window', `
|
|
787
|
+
best-time-to-buy-and-sell-stock
|
|
788
|
+
longest-substring-without-repeating-characters
|
|
789
|
+
minimum-window-substring`],
|
|
790
|
+
['stack', 'Stack', `
|
|
791
|
+
valid-parentheses
|
|
792
|
+
implement-queue-using-stacks
|
|
793
|
+
evaluate-reverse-polish-notation
|
|
794
|
+
min-stack
|
|
795
|
+
basic-calculator
|
|
796
|
+
largest-rectangle-in-histogram`],
|
|
797
|
+
['binary-search', 'Binary Search', `
|
|
798
|
+
binary-search
|
|
799
|
+
first-bad-version
|
|
800
|
+
search-in-rotated-sorted-array
|
|
801
|
+
time-based-key-value-store`],
|
|
802
|
+
['linked-list', 'Linked List', `
|
|
803
|
+
merge-two-sorted-lists
|
|
804
|
+
linked-list-cycle
|
|
805
|
+
reverse-linked-list
|
|
806
|
+
middle-of-the-linked-list
|
|
807
|
+
lru-cache
|
|
808
|
+
merge-k-sorted-lists`],
|
|
809
|
+
['trees', 'Trees', `
|
|
810
|
+
invert-binary-tree
|
|
811
|
+
lowest-common-ancestor-of-a-binary-search-tree
|
|
812
|
+
balanced-binary-tree
|
|
813
|
+
diameter-of-binary-tree
|
|
814
|
+
maximum-depth-of-binary-tree
|
|
815
|
+
binary-tree-level-order-traversal
|
|
816
|
+
validate-binary-search-tree
|
|
817
|
+
lowest-common-ancestor-of-a-binary-tree
|
|
818
|
+
binary-tree-right-side-view
|
|
819
|
+
construct-binary-tree-from-preorder-and-inorder-traversal
|
|
820
|
+
kth-smallest-element-in-a-bst
|
|
821
|
+
serialize-and-deserialize-binary-tree`],
|
|
822
|
+
['heap', 'Heap / Priority Queue', `
|
|
823
|
+
k-closest-points-to-origin
|
|
824
|
+
task-scheduler
|
|
825
|
+
find-median-from-data-stream`],
|
|
826
|
+
['backtracking', 'Backtracking', `
|
|
827
|
+
combination-sum
|
|
828
|
+
permutations
|
|
829
|
+
subsets
|
|
830
|
+
letter-combinations-of-a-phone-number
|
|
831
|
+
word-search`],
|
|
832
|
+
['tries', 'Tries', `
|
|
833
|
+
implement-trie-prefix-tree`],
|
|
834
|
+
['graphs', 'Graphs', `
|
|
835
|
+
flood-fill
|
|
836
|
+
01-matrix
|
|
837
|
+
clone-graph
|
|
838
|
+
course-schedule
|
|
839
|
+
number-of-islands
|
|
840
|
+
rotting-oranges
|
|
841
|
+
accounts-merge
|
|
842
|
+
minimum-height-trees
|
|
843
|
+
word-ladder`],
|
|
844
|
+
['dp-1d', '1-D Dynamic Programming', `
|
|
845
|
+
climbing-stairs
|
|
846
|
+
coin-change
|
|
847
|
+
word-break
|
|
848
|
+
partition-equal-subset-sum
|
|
849
|
+
longest-palindromic-substring
|
|
850
|
+
maximum-profit-in-job-scheduling`],
|
|
851
|
+
['dp-2d', '2-D Dynamic Programming', `
|
|
852
|
+
unique-paths`],
|
|
853
|
+
['greedy', 'Greedy', `
|
|
854
|
+
maximum-subarray`],
|
|
855
|
+
['intervals', 'Intervals', `
|
|
856
|
+
insert-interval
|
|
857
|
+
merge-intervals`],
|
|
858
|
+
['bit-manipulation', 'Bit Manipulation', `
|
|
859
|
+
add-binary`],
|
|
860
|
+
['math-geometry', 'Math & Geometry', `
|
|
861
|
+
spiral-matrix`],
|
|
862
|
+
],
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
// LeetCode's own Top 100 Liked study plan (plan top-100-liked), with its
|
|
866
|
+
// groups exactly as LeetCode's GraphQL gave them on 2026-11-04 (so Binary Tree
|
|
867
|
+
// Maximum Path Sum sits under Binary Search, as LeetCode has it), checked
|
|
868
|
+
// against e2e/leetcode-study-plans.txt by roadmap.test.mjs.
|
|
869
|
+
export const TOP_100_LIKED = defineList({
|
|
870
|
+
id: 'top-100-liked',
|
|
871
|
+
title: 'Top 100 Liked by LeetCode',
|
|
872
|
+
groupNoun: 'topic',
|
|
873
|
+
groups: [
|
|
874
|
+
['backtracking', 'Backtracking', `
|
|
875
|
+
letter-combinations-of-a-phone-number
|
|
876
|
+
generate-parentheses
|
|
877
|
+
combination-sum
|
|
878
|
+
permutations
|
|
879
|
+
n-queens
|
|
880
|
+
subsets
|
|
881
|
+
word-search
|
|
882
|
+
palindrome-partitioning`],
|
|
883
|
+
['binary-search', 'Binary Search', `
|
|
884
|
+
median-of-two-sorted-arrays
|
|
885
|
+
search-in-rotated-sorted-array
|
|
886
|
+
find-first-and-last-position-of-element-in-sorted-array
|
|
887
|
+
search-insert-position
|
|
888
|
+
search-a-2d-matrix
|
|
889
|
+
binary-tree-maximum-path-sum
|
|
890
|
+
find-minimum-in-rotated-sorted-array`],
|
|
891
|
+
['binary-tree', 'Binary Tree', `
|
|
892
|
+
binary-tree-inorder-traversal
|
|
893
|
+
validate-binary-search-tree
|
|
894
|
+
symmetric-tree
|
|
895
|
+
binary-tree-level-order-traversal
|
|
896
|
+
maximum-depth-of-binary-tree
|
|
897
|
+
construct-binary-tree-from-preorder-and-inorder-traversal
|
|
898
|
+
convert-sorted-array-to-binary-search-tree
|
|
899
|
+
flatten-binary-tree-to-linked-list
|
|
900
|
+
binary-tree-right-side-view
|
|
901
|
+
invert-binary-tree
|
|
902
|
+
kth-smallest-element-in-a-bst
|
|
903
|
+
lowest-common-ancestor-of-a-binary-tree
|
|
904
|
+
path-sum-iii
|
|
905
|
+
diameter-of-binary-tree`],
|
|
906
|
+
['dynamic-programming', 'Dynamic Programming', `
|
|
907
|
+
longest-palindromic-substring
|
|
908
|
+
longest-valid-parentheses
|
|
909
|
+
unique-paths
|
|
910
|
+
minimum-path-sum
|
|
911
|
+
climbing-stairs
|
|
912
|
+
edit-distance
|
|
913
|
+
pascals-triangle
|
|
914
|
+
word-break
|
|
915
|
+
maximum-product-subarray
|
|
916
|
+
house-robber
|
|
917
|
+
perfect-squares
|
|
918
|
+
longest-increasing-subsequence
|
|
919
|
+
coin-change
|
|
920
|
+
partition-equal-subset-sum
|
|
921
|
+
longest-common-subsequence`],
|
|
922
|
+
['graph', 'Graph', `
|
|
923
|
+
number-of-islands
|
|
924
|
+
course-schedule
|
|
925
|
+
rotting-oranges`],
|
|
926
|
+
['greedy', 'Greedy', `
|
|
927
|
+
jump-game-ii
|
|
928
|
+
jump-game
|
|
929
|
+
best-time-to-buy-and-sell-stock
|
|
930
|
+
partition-labels`],
|
|
931
|
+
['hashing', 'Hashing', `
|
|
932
|
+
two-sum
|
|
933
|
+
group-anagrams
|
|
934
|
+
longest-consecutive-sequence
|
|
935
|
+
subarray-sum-equals-k`],
|
|
936
|
+
['heap', 'Heap', `
|
|
937
|
+
kth-largest-element-in-an-array
|
|
938
|
+
find-median-from-data-stream
|
|
939
|
+
top-k-frequent-elements`],
|
|
940
|
+
['linked-lists', 'Linked Lists', `
|
|
941
|
+
add-two-numbers
|
|
942
|
+
remove-nth-node-from-end-of-list
|
|
943
|
+
merge-two-sorted-lists
|
|
944
|
+
merge-k-sorted-lists
|
|
945
|
+
swap-nodes-in-pairs
|
|
946
|
+
reverse-nodes-in-k-group
|
|
947
|
+
copy-list-with-random-pointer
|
|
948
|
+
linked-list-cycle
|
|
949
|
+
linked-list-cycle-ii
|
|
950
|
+
lru-cache
|
|
951
|
+
sort-list
|
|
952
|
+
intersection-of-two-linked-lists
|
|
953
|
+
reverse-linked-list
|
|
954
|
+
palindrome-linked-list`],
|
|
955
|
+
['matrix', 'Matrix', `
|
|
956
|
+
rotate-image
|
|
957
|
+
spiral-matrix
|
|
958
|
+
set-matrix-zeroes
|
|
959
|
+
search-a-2d-matrix-ii`],
|
|
960
|
+
['sliding-window', 'Sliding Window', `
|
|
961
|
+
longest-substring-without-repeating-characters
|
|
962
|
+
minimum-window-substring
|
|
963
|
+
sliding-window-maximum
|
|
964
|
+
find-all-anagrams-in-a-string`],
|
|
965
|
+
['stack', 'Stack', `
|
|
966
|
+
valid-parentheses
|
|
967
|
+
largest-rectangle-in-histogram
|
|
968
|
+
min-stack
|
|
969
|
+
decode-string
|
|
970
|
+
daily-temperatures`],
|
|
971
|
+
['two-pointers', 'Two Pointers', `
|
|
972
|
+
container-with-most-water
|
|
973
|
+
3sum
|
|
974
|
+
trapping-rain-water
|
|
975
|
+
move-zeroes`],
|
|
976
|
+
['trie', 'Trie', `
|
|
977
|
+
implement-trie-prefix-tree`],
|
|
978
|
+
['misc', 'Misc', `
|
|
979
|
+
next-permutation
|
|
980
|
+
first-missing-positive
|
|
981
|
+
maximum-subarray
|
|
982
|
+
merge-intervals
|
|
983
|
+
sort-colors
|
|
984
|
+
single-number
|
|
985
|
+
majority-element
|
|
986
|
+
rotate-array
|
|
987
|
+
product-of-array-except-self
|
|
988
|
+
find-the-duplicate-number`],
|
|
989
|
+
],
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
// LeetCode's own Top Interview 150 study plan, with its sections, as
|
|
993
|
+
// LeetCode's GraphQL (studyPlanV2Detail, plan top-interview-150) gave them on
|
|
994
|
+
// 2026-11-04: e2e/leetcode-study-plans.txt, which roadmap.test.mjs compares.
|
|
995
|
+
export const TOP_INTERVIEW_150 = defineList({
|
|
996
|
+
id: 'top-interview-150',
|
|
997
|
+
title: 'Top Interview 150 by LeetCode',
|
|
998
|
+
groupNoun: 'section',
|
|
999
|
+
groups: [
|
|
1000
|
+
['array-string', 'Array / String', `
|
|
1001
|
+
merge-sorted-array
|
|
1002
|
+
remove-element
|
|
1003
|
+
remove-duplicates-from-sorted-array
|
|
1004
|
+
remove-duplicates-from-sorted-array-ii
|
|
1005
|
+
majority-element
|
|
1006
|
+
rotate-array
|
|
1007
|
+
best-time-to-buy-and-sell-stock
|
|
1008
|
+
best-time-to-buy-and-sell-stock-ii
|
|
1009
|
+
jump-game
|
|
1010
|
+
jump-game-ii
|
|
1011
|
+
h-index
|
|
1012
|
+
insert-delete-getrandom-o1
|
|
1013
|
+
product-of-array-except-self
|
|
1014
|
+
gas-station
|
|
1015
|
+
candy
|
|
1016
|
+
trapping-rain-water
|
|
1017
|
+
roman-to-integer
|
|
1018
|
+
integer-to-roman
|
|
1019
|
+
length-of-last-word
|
|
1020
|
+
longest-common-prefix
|
|
1021
|
+
reverse-words-in-a-string
|
|
1022
|
+
zigzag-conversion
|
|
1023
|
+
find-the-index-of-the-first-occurrence-in-a-string
|
|
1024
|
+
text-justification`],
|
|
1025
|
+
['two-pointers', 'Two Pointers', `
|
|
1026
|
+
valid-palindrome
|
|
1027
|
+
is-subsequence
|
|
1028
|
+
two-sum-ii-input-array-is-sorted
|
|
1029
|
+
container-with-most-water
|
|
1030
|
+
3sum`],
|
|
1031
|
+
['sliding-window', 'Sliding Window', `
|
|
1032
|
+
minimum-size-subarray-sum
|
|
1033
|
+
longest-substring-without-repeating-characters
|
|
1034
|
+
substring-with-concatenation-of-all-words
|
|
1035
|
+
minimum-window-substring`],
|
|
1036
|
+
['matrix', 'Matrix', `
|
|
1037
|
+
valid-sudoku
|
|
1038
|
+
spiral-matrix
|
|
1039
|
+
rotate-image
|
|
1040
|
+
set-matrix-zeroes
|
|
1041
|
+
game-of-life`],
|
|
1042
|
+
['hashmap', 'Hashmap', `
|
|
1043
|
+
ransom-note
|
|
1044
|
+
isomorphic-strings
|
|
1045
|
+
word-pattern
|
|
1046
|
+
valid-anagram
|
|
1047
|
+
group-anagrams
|
|
1048
|
+
two-sum
|
|
1049
|
+
happy-number
|
|
1050
|
+
contains-duplicate-ii
|
|
1051
|
+
longest-consecutive-sequence`],
|
|
1052
|
+
['intervals', 'Intervals', `
|
|
1053
|
+
summary-ranges
|
|
1054
|
+
merge-intervals
|
|
1055
|
+
insert-interval
|
|
1056
|
+
minimum-number-of-arrows-to-burst-balloons`],
|
|
1057
|
+
['stack', 'Stack', `
|
|
1058
|
+
valid-parentheses
|
|
1059
|
+
simplify-path
|
|
1060
|
+
min-stack
|
|
1061
|
+
evaluate-reverse-polish-notation
|
|
1062
|
+
basic-calculator`],
|
|
1063
|
+
['linked-list', 'Linked List', `
|
|
1064
|
+
linked-list-cycle
|
|
1065
|
+
add-two-numbers
|
|
1066
|
+
merge-two-sorted-lists
|
|
1067
|
+
copy-list-with-random-pointer
|
|
1068
|
+
reverse-linked-list-ii
|
|
1069
|
+
reverse-nodes-in-k-group
|
|
1070
|
+
remove-nth-node-from-end-of-list
|
|
1071
|
+
remove-duplicates-from-sorted-list-ii
|
|
1072
|
+
rotate-list
|
|
1073
|
+
partition-list
|
|
1074
|
+
lru-cache`],
|
|
1075
|
+
['binary-tree-general', 'Binary Tree General', `
|
|
1076
|
+
maximum-depth-of-binary-tree
|
|
1077
|
+
same-tree
|
|
1078
|
+
invert-binary-tree
|
|
1079
|
+
symmetric-tree
|
|
1080
|
+
construct-binary-tree-from-preorder-and-inorder-traversal
|
|
1081
|
+
construct-binary-tree-from-inorder-and-postorder-traversal
|
|
1082
|
+
populating-next-right-pointers-in-each-node-ii
|
|
1083
|
+
flatten-binary-tree-to-linked-list
|
|
1084
|
+
path-sum
|
|
1085
|
+
sum-root-to-leaf-numbers
|
|
1086
|
+
binary-tree-maximum-path-sum
|
|
1087
|
+
binary-search-tree-iterator
|
|
1088
|
+
count-complete-tree-nodes
|
|
1089
|
+
lowest-common-ancestor-of-a-binary-tree`],
|
|
1090
|
+
['binary-tree-bfs', 'Binary Tree BFS', `
|
|
1091
|
+
binary-tree-right-side-view
|
|
1092
|
+
average-of-levels-in-binary-tree
|
|
1093
|
+
binary-tree-level-order-traversal
|
|
1094
|
+
binary-tree-zigzag-level-order-traversal`],
|
|
1095
|
+
['binary-search-tree', 'Binary Search Tree', `
|
|
1096
|
+
minimum-absolute-difference-in-bst
|
|
1097
|
+
kth-smallest-element-in-a-bst
|
|
1098
|
+
validate-binary-search-tree`],
|
|
1099
|
+
['graph-general', 'Graph General', `
|
|
1100
|
+
number-of-islands
|
|
1101
|
+
surrounded-regions
|
|
1102
|
+
clone-graph
|
|
1103
|
+
evaluate-division
|
|
1104
|
+
course-schedule
|
|
1105
|
+
course-schedule-ii`],
|
|
1106
|
+
['graph-bfs', 'Graph BFS', `
|
|
1107
|
+
snakes-and-ladders
|
|
1108
|
+
minimum-genetic-mutation
|
|
1109
|
+
word-ladder`],
|
|
1110
|
+
['trie', 'Trie', `
|
|
1111
|
+
implement-trie-prefix-tree
|
|
1112
|
+
design-add-and-search-words-data-structure
|
|
1113
|
+
word-search-ii`],
|
|
1114
|
+
['backtracking', 'Backtracking', `
|
|
1115
|
+
letter-combinations-of-a-phone-number
|
|
1116
|
+
combinations
|
|
1117
|
+
permutations
|
|
1118
|
+
combination-sum
|
|
1119
|
+
n-queens-ii
|
|
1120
|
+
generate-parentheses
|
|
1121
|
+
word-search`],
|
|
1122
|
+
['divide-conquer', 'Divide & Conquer', `
|
|
1123
|
+
convert-sorted-array-to-binary-search-tree
|
|
1124
|
+
sort-list
|
|
1125
|
+
construct-quad-tree
|
|
1126
|
+
merge-k-sorted-lists`],
|
|
1127
|
+
['kadane', "Kadane's Algorithm", `
|
|
1128
|
+
maximum-subarray
|
|
1129
|
+
maximum-sum-circular-subarray`],
|
|
1130
|
+
['binary-search', 'Binary Search', `
|
|
1131
|
+
search-insert-position
|
|
1132
|
+
search-a-2d-matrix
|
|
1133
|
+
find-peak-element
|
|
1134
|
+
search-in-rotated-sorted-array
|
|
1135
|
+
find-first-and-last-position-of-element-in-sorted-array
|
|
1136
|
+
find-minimum-in-rotated-sorted-array
|
|
1137
|
+
median-of-two-sorted-arrays`],
|
|
1138
|
+
['heap', 'Heap', `
|
|
1139
|
+
kth-largest-element-in-an-array
|
|
1140
|
+
ipo
|
|
1141
|
+
find-k-pairs-with-smallest-sums
|
|
1142
|
+
find-median-from-data-stream`],
|
|
1143
|
+
['bit-manipulation', 'Bit Manipulation', `
|
|
1144
|
+
add-binary
|
|
1145
|
+
reverse-bits
|
|
1146
|
+
number-of-1-bits
|
|
1147
|
+
single-number
|
|
1148
|
+
single-number-ii
|
|
1149
|
+
bitwise-and-of-numbers-range`],
|
|
1150
|
+
['math', 'Math', `
|
|
1151
|
+
palindrome-number
|
|
1152
|
+
plus-one
|
|
1153
|
+
factorial-trailing-zeroes
|
|
1154
|
+
sqrtx
|
|
1155
|
+
powx-n
|
|
1156
|
+
max-points-on-a-line`],
|
|
1157
|
+
['dp-1d', '1D DP', `
|
|
1158
|
+
climbing-stairs
|
|
1159
|
+
house-robber
|
|
1160
|
+
word-break
|
|
1161
|
+
coin-change
|
|
1162
|
+
longest-increasing-subsequence`],
|
|
1163
|
+
['dp-multi', 'Multidimensional DP', `
|
|
1164
|
+
triangle
|
|
1165
|
+
minimum-path-sum
|
|
1166
|
+
unique-paths-ii
|
|
1167
|
+
longest-palindromic-substring
|
|
1168
|
+
interleaving-string
|
|
1169
|
+
edit-distance
|
|
1170
|
+
best-time-to-buy-and-sell-stock-iii
|
|
1171
|
+
best-time-to-buy-and-sell-stock-iv
|
|
1172
|
+
maximal-square`],
|
|
1173
|
+
],
|
|
1174
|
+
});
|
|
1175
|
+
|
|
1176
|
+
// LeetCode's own SQL 50 study plan (database problems, plan top-sql-50), with
|
|
1177
|
+
// its sections, checked against e2e/leetcode-study-plans.txt the same way.
|
|
1178
|
+
export const SQL_50 = defineList({
|
|
1179
|
+
id: 'sql-50',
|
|
1180
|
+
title: 'SQL 50',
|
|
1181
|
+
groupNoun: 'section',
|
|
1182
|
+
groups: [
|
|
1183
|
+
['select', 'Select', `
|
|
1184
|
+
recyclable-and-low-fat-products
|
|
1185
|
+
find-customer-referee
|
|
1186
|
+
big-countries
|
|
1187
|
+
article-views-i
|
|
1188
|
+
invalid-tweets`],
|
|
1189
|
+
['basic-joins', 'Basic Joins', `
|
|
1190
|
+
replace-employee-id-with-the-unique-identifier
|
|
1191
|
+
product-sales-analysis-i
|
|
1192
|
+
customer-who-visited-but-did-not-make-any-transactions
|
|
1193
|
+
rising-temperature
|
|
1194
|
+
average-time-of-process-per-machine
|
|
1195
|
+
employee-bonus
|
|
1196
|
+
students-and-examinations
|
|
1197
|
+
managers-with-at-least-5-direct-reports
|
|
1198
|
+
confirmation-rate`],
|
|
1199
|
+
['basic-aggregate', 'Basic Aggregate Functions', `
|
|
1200
|
+
not-boring-movies
|
|
1201
|
+
average-selling-price
|
|
1202
|
+
project-employees-i
|
|
1203
|
+
percentage-of-users-attended-a-contest
|
|
1204
|
+
queries-quality-and-percentage
|
|
1205
|
+
monthly-transactions-i
|
|
1206
|
+
immediate-food-delivery-ii
|
|
1207
|
+
game-play-analysis-iv`],
|
|
1208
|
+
['sorting-grouping', 'Sorting and Grouping', `
|
|
1209
|
+
number-of-unique-subjects-taught-by-each-teacher
|
|
1210
|
+
user-activity-for-the-past-30-days-i
|
|
1211
|
+
product-sales-analysis-iii
|
|
1212
|
+
classes-with-at-least-5-students
|
|
1213
|
+
find-followers-count
|
|
1214
|
+
biggest-single-number
|
|
1215
|
+
customers-who-bought-all-products`],
|
|
1216
|
+
['advanced-select-joins', 'Advanced Select and Joins', `
|
|
1217
|
+
the-number-of-employees-which-report-to-each-employee
|
|
1218
|
+
primary-department-for-each-employee
|
|
1219
|
+
triangle-judgement
|
|
1220
|
+
consecutive-numbers
|
|
1221
|
+
product-price-at-a-given-date
|
|
1222
|
+
last-person-to-fit-in-the-bus
|
|
1223
|
+
count-salary-categories`],
|
|
1224
|
+
['subqueries', 'Subqueries', `
|
|
1225
|
+
employees-whose-manager-left-the-company
|
|
1226
|
+
exchange-seats
|
|
1227
|
+
movie-rating
|
|
1228
|
+
restaurant-growth
|
|
1229
|
+
friend-requests-ii-who-has-the-most-friends
|
|
1230
|
+
investments-in-2016
|
|
1231
|
+
department-top-three-salaries`],
|
|
1232
|
+
['advanced-string', 'Advanced String Functions / Regex / Clause', `
|
|
1233
|
+
fix-names-in-a-table
|
|
1234
|
+
patients-with-a-condition
|
|
1235
|
+
delete-duplicate-emails
|
|
1236
|
+
second-highest-salary
|
|
1237
|
+
group-sold-products-by-the-date
|
|
1238
|
+
list-the-products-ordered-in-a-period
|
|
1239
|
+
find-users-with-valid-e-mails`],
|
|
1240
|
+
],
|
|
1241
|
+
});
|
|
1242
|
+
|
|
1243
|
+
// Every list, in the order the Progress tab offers them.
|
|
1244
|
+
export const LISTS = [NEETCODE_150, NEETCODE_250, BLIND_75, GRIND_75, TOP_100_LIKED, TOP_INTERVIEW_150, SQL_50];
|
|
1245
|
+
export const ROADMAPS = Object.fromEntries(LISTS.map((list) => [list.id, list]));
|
|
1246
|
+
export const DEFAULT_LIST_ID = NEETCODE_150.id;
|
|
1247
|
+
|
|
1248
|
+
// The list with this id; anything unknown (an old or damaged stored value)
|
|
1249
|
+
// means the default, NeetCode 150.
|
|
1250
|
+
export function listById(id) {
|
|
1251
|
+
return (typeof id === 'string' && Object.hasOwn(ROADMAPS, id) && ROADMAPS[id]) || NEETCODE_150;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
export function problemUrl(slug) {
|
|
1255
|
+
return `https://leetcode.com/problems/${slug}/`;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
function index(roadmap) {
|
|
1259
|
+
const bySlug = new Map();
|
|
1260
|
+
for (const topic of roadmap.topics) for (const p of topic.problems) bySlug.set(p.slug, p);
|
|
1261
|
+
return bySlug;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
// The problem as this list has it, or null when it is not on the list.
|
|
1265
|
+
export function problemInList(roadmap, slug) {
|
|
1266
|
+
return index(roadmap).get(slug) || null;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
// Solved and total counts per topic and overall. `solved` is any iterable of
|
|
1270
|
+
// slugs (the student's accepted submissions); slugs outside the roadmap are
|
|
1271
|
+
// ignored for the counts.
|
|
1272
|
+
export function progress(roadmap, solved) {
|
|
1273
|
+
const done = new Set(solved);
|
|
1274
|
+
const topics = roadmap.topics.map((topic) => {
|
|
1275
|
+
const solvedCount = topic.problems.filter((p) => done.has(p.slug)).length;
|
|
1276
|
+
return { id: topic.id, title: topic.title, solved: solvedCount, total: topic.problems.length, complete: solvedCount === topic.problems.length };
|
|
1277
|
+
});
|
|
1278
|
+
const solvedTotal = topics.reduce((n, t) => n + t.solved, 0);
|
|
1279
|
+
const total = topics.reduce((n, t) => n + t.total, 0);
|
|
1280
|
+
return { topics, solved: solvedTotal, total };
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
// A topic is unlocked when every topic that points to it has at least one
|
|
1284
|
+
// problem solved (the roadmap is a guide, not a gate: nothing is blocked,
|
|
1285
|
+
// this only orders the suggestions). A list without edges has every group
|
|
1286
|
+
// unlocked, so its order alone decides.
|
|
1287
|
+
export function unlockedTopics(roadmap, solved) {
|
|
1288
|
+
const done = new Set(solved);
|
|
1289
|
+
const started = new Set(roadmap.topics.filter((t) => t.problems.some((p) => done.has(p.slug))).map((t) => t.id));
|
|
1290
|
+
return new Set(
|
|
1291
|
+
roadmap.topics
|
|
1292
|
+
.filter((t) => roadmap.edges.filter(([, to]) => to === t.id).every(([from]) => started.has(from)))
|
|
1293
|
+
.map((t) => t.id)
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// What to do next, in the list's order: the first unsolved problems of the
|
|
1298
|
+
// earliest topic that is unlocked and not finished.
|
|
1299
|
+
export function nextOnRoadmap(roadmap, solved, { count = 1 } = {}) {
|
|
1300
|
+
const done = new Set(solved);
|
|
1301
|
+
const open = unlockedTopics(roadmap, done);
|
|
1302
|
+
const out = [];
|
|
1303
|
+
for (const topic of roadmap.topics) {
|
|
1304
|
+
if (!open.has(topic.id)) continue;
|
|
1305
|
+
for (const p of topic.problems) {
|
|
1306
|
+
if (!done.has(p.slug)) out.push(p);
|
|
1307
|
+
if (out.length >= count) return out;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
return out;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// More of the same kind: unsolved problems in the topic of the one just
|
|
1314
|
+
// solved (its subject, on a list that has subjects), easiest first.
|
|
1315
|
+
export function moreOfTopic(roadmap, solved, slug, { count = 1 } = {}) {
|
|
1316
|
+
const done = new Set(solved);
|
|
1317
|
+
const problem = index(roadmap).get(slug);
|
|
1318
|
+
if (!problem) return { topic: null, problems: [] };
|
|
1319
|
+
const topic = roadmap.subjects ? roadmap.subjects.find((t) => t.id === problem.subject) : roadmap.topics.find((t) => t.id === problem.topic);
|
|
1320
|
+
const rank = { Easy: 0, Medium: 1, Hard: 2 };
|
|
1321
|
+
const problems = topic.problems
|
|
1322
|
+
.filter((p) => !done.has(p.slug) && p.slug !== slug)
|
|
1323
|
+
.sort((a, b) => rank[a.difficulty] - rank[b.difficulty])
|
|
1324
|
+
.slice(0, count);
|
|
1325
|
+
return { topic: { id: topic.id, title: topic.title }, problems };
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// Everything the "nice job" message needs after an accepted submission.
|
|
1329
|
+
export function suggestAfterSolve(roadmap, solved, slug, { count = 1 } = {}) {
|
|
1330
|
+
const done = new Set(solved);
|
|
1331
|
+
done.add(slug);
|
|
1332
|
+
return {
|
|
1333
|
+
roadmap: { id: roadmap.id, title: roadmap.title },
|
|
1334
|
+
agenda: nextOnRoadmap(roadmap, done, { count }),
|
|
1335
|
+
sameTopic: moreOfTopic(roadmap, done, slug, { count }),
|
|
1336
|
+
};
|
|
1337
|
+
}
|