Data Structures & Algorithms (DSA) Module 1 – Foundations: problems, correctness and complexity
The DSA toolkit in Python, JS, Java, C++ and Go
Map stacks, queues, hash maps, ordered maps and heaps to the standard libraries of Python, JavaScript, Java, C++ and Go, with documented costs and traps.
What you will learn
- Map each abstract data type to its standard-library type in five languages
- State the documented cost of the core operations
- Avoid the version-specific traps of each standard library
Before you start
On this page
Most of the algorithms in this track are built from a handful of abstract data types: a stack, a queue, a hash map or set, an ordered map and a priority queue. Every language’s standard library implements some of them, under different names, with different defaults and with different promises about speed. This lesson maps them across the five languages the track uses, lists the costs their documentation actually promises, and collects the traps that catch people when they switch languages or versions.
One program in two languages
This program uses all five abstract data types once each. The Python and JavaScript versions do the same work and print the same lines; choose a tab to compare them:
Python · toolkit/toolkit.py
import bisect
import heapq
from collections import deque
# Stack: a list, pushing and popping at the end.
history = []
for page in ["home", "search", "results"]:
history.append(page)
print(f"stack: back from {history.pop()} to {history[-1]}")
# Queue: collections.deque, adding at the back and taking from the front.
line = deque(["asha", "ben", "chen"])
line.append("dev")
print(f"queue: serve {line.popleft()}, then {line[0]} is first")
# Hash map: dict, counting words (keys stay in the order they were first added).
counts = {}
for word in "to be or not to be".split():
counts[word] = counts.get(word, 0) + 1
print("map:", " ".join(f"{word}={n}" for word, n in counts.items()))
# Ordered keys: no tree map in the standard library, so a sorted list and binary search.
scores = []
for score in [70, 45, 90, 60]:
bisect.insort(scores, score)
first = scores[bisect.bisect_left(scores, 65)]
print(f"sorted: {', '.join(map(str, scores))}; first score >= 65: {first}")
# Priority queue: heapq keeps a min-heap in a list; (priority, task) pairs pop lowest first.
tasks = []
for priority, task in [(3, "email"), (1, "fix bug"), (2, "review")]:
heapq.heappush(tasks, (priority, task))
print("heap:", ", ".join(heapq.heappop(tasks)[1] for _ in range(len(tasks)))) Output
stack: back from results to search queue: serve asha, then ben is first map: to=2 be=2 or=1 not=1 sorted: 45, 60, 70, 90; first score >= 65: 70 heap: fix bug, review, email
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 toolkit.py
JavaScript · toolkit/toolkit.mjs
// Stack: an array, pushing and popping at the end.
const history = [];
for (const page of ['home', 'search', 'results']) history.push(page);
console.log(`stack: back from ${history.pop()} to ${history.at(-1)}`);
// Queue: there is no deque, and shift() moves every element, so keep the index of the front instead.
const line = ['asha', 'ben', 'chen'];
let front = 0;
line.push('dev');
console.log(`queue: serve ${line[front++]}, then ${line[front]} is first`);
// Hash map: Map, counting words (keys stay in the order they were first added).
const counts = new Map();
for (const word of 'to be or not to be'.split(' ')) counts.set(word, (counts.get(word) ?? 0) + 1);
console.log(`map: ${[...counts].map(([word, n]) => `${word}=${n}`).join(' ')}`);
// Ordered keys: no tree map either, so a sorted array and a binary search written by hand.
function lowerBound(sorted, x) {
let low = 0;
let high = sorted.length;
while (low < high) {
const middle = (low + high) >>> 1;
if (sorted[middle] < x) low = middle + 1;
else high = middle;
}
return low;
}
const scores = [];
for (const score of [70, 45, 90, 60]) scores.splice(lowerBound(scores, score), 0, score);
console.log(`sorted: ${scores.join(', ')}; first score >= 65: ${scores[lowerBound(scores, 65)]}`);
// Priority queue: no heap in JavaScript, so a small binary min-heap of [priority, task] pairs.
const before = (a, b) => a[0] < b[0] || (a[0] === b[0] && a[1] < b[1]);
class MinHeap {
items = [];
push(item) {
const a = this.items;
a.push(item);
for (let i = a.length - 1; i > 0 && before(a[i], a[(i - 1) >> 1]); i = (i - 1) >> 1) {
[a[i], a[(i - 1) >> 1]] = [a[(i - 1) >> 1], a[i]];
}
}
pop() {
const a = this.items;
const top = a[0];
const last = a.pop();
if (a.length) {
a[0] = last;
for (let i = 0; ; ) {
const left = 2 * i + 1;
const right = left + 1;
let smallest = i;
if (left < a.length && before(a[left], a[smallest])) smallest = left;
if (right < a.length && before(a[right], a[smallest])) smallest = right;
if (smallest === i) break;
[a[i], a[smallest]] = [a[smallest], a[i]];
i = smallest;
}
}
return top;
}
get size() {
return this.items.length;
}
}
const tasks = new MinHeap();
for (const pair of [[3, 'email'], [1, 'fix bug'], [2, 'review']]) tasks.push(pair);
const order = [];
while (tasks.size) order.push(tasks.pop()[1]);
console.log(`heap: ${order.join(', ')}`); Output
stack: back from results to search queue: serve asha, then ben is first map: to=2 be=2 or=1 not=1 sorted: 45, 60, 70, 90; first score >= 65: 70 heap: fix bug, review, email
Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node toolkit.mjs
Runs on this device, in your browser. The first run of each language downloads it: Python (about 13.5 MB) or JavaScript (about 0.6 MB), which is kept for the next runs.
Your run, in this browser
Python has every structure it needs in the standard library: a list as the stack, collections.deque as the queue,
a dict, bisect for the sorted list and heapq for the priority queue. The JavaScript version had to supply three
of its own: a front index instead of a deque, a binary search instead of a sorted-container type, and a short
binary heap.
The sections below take one language each: which type to use for each abstract data type, the costs its documentation promises, and its traps. Java, C++ and Go programs are not run on this page; what it says about them comes from each language’s own documentation and specification, listed under References.
Python 3.14
- Dynamic array and stack:
list, withappend()andpop()at the end. - Queue or deque:
collections.deque. - Hash map and set:
dictandset. - Ordered map: none in the standard library. Keep a sorted
listand search it withbisect. - Priority queue:
heapq, functions that keep a min-heap inside an ordinary list. - Graphs:
graphlib.TopologicalSortersorts a dependency graph (from Python 3.9).
Python documents the costs of its built-in types on one page of its documentation, plus the pages of deque,
heapq and bisect:
| Operation | Time | Extra space |
|---|---|---|
| list.append(x), list.pop() | O(1) | O(1) |
| list.pop(0), list.insert(0, x) | O(n) | O(1) |
| x in list | O(n) | O(1) |
| deque: append, appendleft, pop, popleft | O(1) | O(1) |
| dict and set: get, set, delete, in | O(1) | O(1) |
| heapq.heapify(list) | O(n) | O(1) |
| heapq.heappush, heapq.heappop | O(log n) | O(1) |
| bisect.bisect_left | O(log n) | O(1) |
| bisect.insort | O(n) | O(1) |
The list costs at the end of the list are amortised: an occasional append copies the whole list into more room.
pop(0) and insert(0, x) move every later element. The dict and set costs are averages; when many keys collide,
an operation can take O(n). Indexing the middle of a deque is O(n), and insort is O(n) because inserting moves
elements even though the search is fast. The heapq page states the linear heapify and, in its section on the
theory, that taking out the smallest item is logarithmic; a push climbs the same tree at most one level per step, so
it is logarithmic too.
The max-heap functions of heapq (heapify_max, heappush_max, heappop_max and two more) are new in Python
3.14; before that, the usual workaround was to push negated values. bisect takes a key= argument only from 3.10.
Two limits catch algorithm code in every recent version: recursion stops at about 1,000 nested calls by default, and
converting an integer of more than 4,300 decimal digits to a string raises ValueError (a protection against very
slow conversions). A program can ask its interpreter directly:
import bisect
import heapq
import inspect
import itertools
import sys
def has(found):
return "yes" if found else "no "
try:
graphlib = __import__("graphlib")
except ImportError:
graphlib = None
print(f"Python {sys.version_info.major}.{sys.version_info.minor}")
print(f"{has(hasattr(heapq, 'heapify_max'))} heapq max-heap functions (3.14)")
print(f"{has(hasattr(itertools, 'batched'))} itertools.batched (3.12)")
print(f"{has('key' in inspect.signature(bisect.bisect_left).parameters)} bisect with key= (3.10)")
print(f"{has(hasattr(itertools, 'pairwise'))} itertools.pairwise (3.10)")
print(f"{has(graphlib is not None)} graphlib.TopologicalSorter (3.9)")
print(f"recursion limit: {sys.getrecursionlimit()}")
print(f"digits allowed in str(int): {sys.get_int_max_str_digits()}")
try:
str(10**5000)
except ValueError as error:
print(f"str(10**5000) raises {type(error).__name__}: the number has 5,001 digits") Output
Python 3.14 yes heapq max-heap functions (3.14) yes itertools.batched (3.12) yes bisect with key= (3.10) yes itertools.pairwise (3.10) yes graphlib.TopologicalSorter (3.9) recursion limit: 1000 digits allowed in str(int): 4300 str(10**5000) raises ValueError: the number has 5,001 digits
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 features.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
Pyodide, the Python of this site’s Run buttons, is CPython 3.14.2 and prints the same lines.
JavaScript (ECMAScript 2026)
- Dynamic array and stack:
Array, withpush()andpop(). - Queue or deque: none. Use an
Arrayand an index of its front, as the toolkit program does. - Hash map and set:
MapandSet. - Ordered map: none.
- Priority queue: none. Write a binary heap, as the toolkit program does.
The ECMAScript standard promises less than the other languages’ documentation. It requires Map and Set to be
implemented with hash tables or other mechanisms whose access time is, on average, less than linear in the number of
elements, and it defines iteration in insertion order. It states no cost for array methods. Its algorithm for
shift() moves every remaining element down by one place, which is why the toolkit program keeps a front index
instead.
Engines add new ECMAScript features at different times, so the same file can work in one and fail in another.
structuredClone() is not ECMAScript at all but a web platform function that browsers and Node.js provide. Test for a
feature before relying on it:
// Which optional features does this JavaScript engine have? Test for a feature before you rely on it.
const has = (found) => (found ? 'yes' : 'no ');
const engine = typeof process === 'object' ? `Node.js ${process.versions.node} (V8 ${process.versions.v8})` : 'not Node.js';
console.log(`engine: ${engine}`);
console.log(`${has(typeof Set.prototype.union === 'function')} Set.prototype.union and friends (ES2025)`);
console.log(`${has(typeof globalThis.Iterator?.prototype?.map === 'function')} iterator helpers such as Iterator.prototype.map (ES2025)`);
console.log(`${has(typeof Math.sumPrecise === 'function')} Math.sumPrecise (ES2026)`);
console.log(`${has(typeof Map.prototype.getOrInsert === 'function')} Map.prototype.getOrInsert (ES2026)`);
console.log(`${has(typeof Array.fromAsync === 'function')} Array.fromAsync (ES2026)`);
console.log(`${has(typeof structuredClone === 'function')} structuredClone (a web platform function, not ECMAScript)`);
console.log(`Number.MAX_SAFE_INTEGER: ${Number.MAX_SAFE_INTEGER}`);
console.log(`2 ** 53 + 1 as a Number: ${2 ** 53 + 1}, as a BigInt: ${2n ** 53n + 1n}`); Output
engine: Node.js 24.21.0 (V8 13.6.233.17-node.53) yes Set.prototype.union and friends (ES2025) yes iterator helpers such as Iterator.prototype.map (ES2025) no Math.sumPrecise (ES2026) no Map.prototype.getOrInsert (ES2026) yes Array.fromAsync (ES2026) yes structuredClone (a web platform function, not ECMAScript) Number.MAX_SAFE_INTEGER: 9007199254740991 2 ** 53 + 1 as a Number: 9007199254740992, as a BigInt: 9007199254740993
Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node features.mjs
Runs on this device, in your browser. The first run downloads JavaScript (about 0.6 MB), which is kept for the next runs.
Your run, in this browser
Version note
In your browser, this file runs in QuickJS (quickjs-emscripten 0.32.0). That engine has two ES2026 features that
Node.js 24 lacks, Math.sumPrecise and Map.prototype.getOrInsert, but not Array.fromAsync, and it has no
structuredClone, because that comes from the web platform, not from the language.
In your browser, QuickJS (quickjs-emscripten 0.32.0) prints:
engine: not Node.js yes Set.prototype.union and friends (ES2025) yes iterator helpers such as Iterator.prototype.map (ES2025) yes Math.sumPrecise (ES2026) yes Map.prototype.getOrInsert (ES2026) no Array.fromAsync (ES2026) no structuredClone (a web platform function, not ECMAScript) Number.MAX_SAFE_INTEGER: 9007199254740991 2 ** 53 + 1 as a Number: 9007199254740992, as a BigInt: 9007199254740993
Two more traps are in the language itself. Above Number.MAX_SAFE_INTEGER, 2⁵³ − 1, a Number can no longer hold
every integer: neighbouring integers share one value, so 2 ** 53 + 1 comes out as 2⁵³, as the last line of the
probe shows. Use BigInt for integers that large. And
Array.prototype.sort() without a compare function compares elements as strings, so [10, 9, 1].sort() gives
[1, 10, 9]; pass (a, b) => a - b to sort numbers.
Java 25
- Dynamic array:
ArrayList. - Stack, queue and deque:
ArrayDeque. Its documentation says it is likely to be faster thanStackused as a stack and faster thanLinkedListused as a queue, and the documentation ofStackrecommendsDequeimplementations in its place. - Hash map and set:
HashMapandHashSet. - Ordered map and set:
TreeMapandTreeSet, red-black trees. - Priority queue:
PriorityQueue, smallest element first. - Sorting and binary search:
List.sortandCollections.binarySearch.
| Operation | Time | Extra space |
|---|---|---|
| ArrayList.add | O(1) | O(1) |
| ArrayList.get, set | O(1) | O(1) |
| ArrayDeque: push, pop, offer, poll | O(1) | O(1) |
| HashMap.get, put | O(1) | O(1) |
| TreeMap: containsKey, get, put, remove | O(log n) | O(1) |
| PriorityQueue: offer, poll | O(log n) | O(1) |
| PriorityQueue.peek | O(1) | O(1) |
ArrayList.add and the ArrayDeque operations are amortised, and contains and remove(Object) on an
ArrayDeque or a PriorityQueue are O(n). HashMap promises constant time only if the hash function spreads the
keys well among its buckets, while TreeMap guarantees its log n.
JDK 25 makes compact source files standard (JEP 512): a file may contain just void main() { IO.println("hi"); },
with no class around it. JDK 21 to 24 had only previews of the feature, switched on with --enable-preview, and
they differ from the final version (in the last preview the IO class was still in java.io, not java.lang), so
write such files for JDK 25 or later. Two older traps matter more for algorithms:
==on boxed numbers.Integervalues are objects, and==compares whether two references are the same object. The Java Language Specification guarantees shared objects only for small constant values (-128 to 127), so compareIntegervalues withequals(), or unbox them toint.- Comparators that subtract.
(x, y) -> x - yoverflows when the values are far apart, becauseintarithmetic wraps around, and the sort then puts large values in the wrong place. UseInteger.compare(x, y)orComparator.naturalOrder().
C++23
- Dynamic array:
std::vector. - Stack and queue:
std::stackandstd::queue, adaptors overstd::dequeby default. - Hash map and set:
std::unordered_mapandstd::unordered_set. - Ordered map and set:
std::mapandstd::set; from C++23 alsostd::flat_map. - Priority queue:
std::priority_queue, largest element first. - Sorting and binary search:
std::sortandstd::lower_bound.
| Operation | Time | Extra space |
|---|---|---|
| vector::push_back | O(1) | O(1) |
| unordered_map: find, insert | O(1) | O(1) |
| map and set: find, insert | O(log n) | O(1) |
| priority_queue::push | O(log n) | O(1) |
| priority_queue::top | O(1) | O(1) |
push_back is amortised constant. The unordered containers are O(1) on average and O(n) in the worst case, and
priority_queue::push makes at most log n comparisons.
std::priority_queueis a max-heap. It compares withstd::less, so the largest element is on top, the opposite of Python, Java and Go. Usestd::greater<T>as the third template argument for a min-heap.- Comparators must be a strict weak ordering. The standard requires it of every comparison passed to a sorting
algorithm, and
<=is not one: a strict ordering never says that an element comes before itself, butx <= xis true. When a program breaks a requirement like this, the standard places no requirements on what happens (undefined behaviour), so the result may be a wrong order or a crash. map[key]inserts. Reading a missing key withoperator[]adds it with a default value; usefind()orcontains()to look without changing the map.std::flat_mapneeds C++23. It keeps its keys sorted in a sequence container, so lookups are binary searches, but the standard makes inserting or erasing one element linear in the size of the map.
Go 1.27
- Dynamic array and stack: a slice, with
appendands[:len(s)-1]. - Queue: none. Use a slice and an index of its front, or
container/list, a doubly linked list. - Hash map and set: the built-in
map; for a set, Effective Go suggests a map withboolvalues. - Ordered map: none. Sort the keys with
slices.Sortwhen you need them in order. - Priority queue:
container/heap, smallest first, on a type you write. - Sorting and binary search:
slices.Sortandslices.BinarySearch.
| Operation | Time | Extra space |
|---|---|---|
| heap.Init | O(n) | O(1) |
| heap.Push, heap.Pop | O(log n) | O(1) |
| slices.Insert(s, i, v) | O(n) | O(1) |
The specification states no cost for the built-in map; the Go team describes the runtime’s map as a hash table,
built since Go 1.24 on a design called Swiss Tables. slices.Insert is documented as O(len(s) + len(v)): every
element after the insertion point moves.
The best-known trap is the order of a map. The specification says it in one sentence:
The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next.
So sort the keys first whenever output must be repeatable. Two more traps:
container/heapneeds your type. You writeLen,Less,Swap,PushandPopfor your slice type, then callheap.Pushandheap.Popfrom the package; the documentation notes that thePushandPopmethods are for the package to call, not for you.- Generic methods are new in Go 1.27: a method may now declare its own type parameters. Code that uses them does not compile with Go 1.26 or earlier.
GATE CS
The Programming and Data Structures section of the GATE 2027 syllabus for Computer Science and Information Technology begins with “Programming in C” and goes on to list arrays, stacks, queues, linked lists, trees, binary search trees, binary heaps and graphs. C has arrays, but its standard library has none of the containers in this lesson, so for GATE you study how each structure is built and what its operations cost, not a library’s names for them.
Port it yourself
The exercise below asks you to port this small task board from Python to JavaScript. It uses four of the structures: a queue for the order of tasks, a hash map for owners, a min-heap of deadlines and a stack for undo. A task that has started or been undone is only marked as gone in a set; the queue, the heap and the stack drop it when it comes up next, instead of digging it out of the middle:
import heapq
from collections import deque
def run_task_board(commands):
"""Run the commands of a small task board and return the lines it prints."""
waiting = deque() # queue: tasks in the order they were added
owners = {} # hash map: task -> owner
deadlines = [] # min-heap of (day, task): the earliest day first, then the task's name
added = [] # stack: the tasks in the order they were added, for undo
gone = set() # tasks that have started or been undone
lines = []
for command in commands:
name, *args = command.split()
if name == "add":
task, owner, day = args[0], args[1], int(args[2])
waiting.append(task)
owners[task] = owner
heapq.heappush(deadlines, (day, task))
added.append(task)
lines.append(f"added {task} for {owner}, due on day {day}")
elif name == "next":
while waiting and waiting[0] in gone:
waiting.popleft()
if waiting:
task = waiting.popleft()
gone.add(task)
lines.append(f"{owners[task]} starts {task}")
else:
lines.append("no task is waiting")
elif name == "urgent":
while deadlines and deadlines[0][1] in gone:
heapq.heappop(deadlines)
if deadlines:
day, task = deadlines[0]
lines.append(f"most urgent: {task}, due on day {day}")
else:
lines.append("nothing is urgent")
elif name == "undo":
while added and added[-1] in gone:
added.pop()
if added:
task = added.pop()
gone.add(task)
lines.append(f"undid {task}")
else:
lines.append("nothing to undo")
return lines
DEMO = [
"add slides asha 5",
"add report ben 3",
"add invoice chen 3",
"urgent",
"next",
"undo",
"urgent",
"next",
"next",
]
for line in run_task_board(DEMO):
print(line) Output
added slides for asha, due on day 5 added report for ben, due on day 3 added invoice for chen, due on day 3 most urgent: invoice, due on day 3 asha starts slides undid invoice most urgent: report, due on day 3 ben starts report no task is waiting
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 task_board.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
Key takeaways
- Python’s standard library covers stacks, queues, hash maps and heaps but has no ordered map. JavaScript has
arrays,
MapandSetonly. Java and C++ include balanced-tree maps; Go has slices, maps andcontainer/heap. - Rely on documented costs:
dequeandArrayDequefor queues, hash maps for average O(1) lookups, tree maps for guaranteed O(log n), heaps for O(log n) push and pop.list.pop(0),x in listand JavaScript’sshift()are linear. - Know the defaults: C++’s priority queue gives the largest element first, the others the smallest; Go’s map order is unspecified; JavaScript sorts as strings unless you pass a compare function.
- Check versions:
heapqmax-heaps need Python 3.14, compact Java source files need JDK 25,std::flat_mapneeds C++23, generic methods need Go 1.27, and each JavaScript engine has its own set of the newest features.
Exercise
Exercise · Medium · JavaScript
Port the task board from Python to JavaScript
Port the lesson's task_board.py to JavaScript. Write runTaskBoard(commands): it takes an array of command strings and returns an array of the lines the Python version prints for them, word for word. The commands are:
- add TASK OWNER DAY: add a task, its owner and the day it is due. Prints added TASK for OWNER, due on day DAY. - next: the owner starts the task that has waited longest. Prints OWNER starts TASK, or no task is waiting. - urgent: names the waiting task with the earliest day; on equal days, the task whose name comes first. Prints most urgent: TASK, due on day DAY, or nothing is urgent. - undo: removes the most recently added task that has not started. Prints undid TASK, or nothing to undo.
A task that has started or been undone is gone: next, urgent and undo skip it. Task names are never repeated.
JavaScript has no deque and no heap, so choose a replacement for each: an array with an index of its front for the queue, and a small binary heap, or another way to find the earliest deadline, for urgent. The tests only compare the lines your function returns.
Starter code · task_board.mjs
/**
* Runs the commands of the task board and returns the lines it prints, exactly like run_task_board in the lesson's
* task_board.py: "add TASK OWNER DAY", "next", "urgent" and "undo".
*/
export function runTaskBoard(commands) {
const lines = [];
// A queue, a Map of owners, the deadlines, a stack of added tasks and a Set of tasks that are gone.
return lines;
} The sample tests · task_board.test.mjs
import { test, assert } from 'toolverse:test';
import { runTaskBoard } from './task_board.mjs';
test('prints what task_board.py prints for its demo', () =>
assert.deepEqual(runTaskBoard(['add slides asha 5', 'add report ben 3', 'add invoice chen 3', 'urgent', 'next', 'undo', 'urgent', 'next', 'next']), [
'added slides for asha, due on day 5',
'added report for ben, due on day 3',
'added invoice for chen, due on day 3',
'most urgent: invoice, due on day 3',
'asha starts slides',
'undid invoice',
'most urgent: report, due on day 3',
'ben starts report',
'no task is waiting',
]));
test('says so when the board is empty', () =>
assert.deepEqual(runTaskBoard(['next', 'urgent', 'undo']), ['no task is waiting', 'nothing is urgent', 'nothing to undo']));
test('serves tasks first in, first out', () =>
assert.deepEqual(runTaskBoard(['add a ann 9', 'add b bob 1', 'add c cy 5', 'next', 'next', 'next']), [
'added a for ann, due on day 9',
'added b for bob, due on day 1',
'added c for cy, due on day 5',
'ann starts a',
'bob starts b',
'cy starts c',
]));
test('picks the earliest day, then the first name, and skips tasks that are gone', () =>
assert.deepEqual(runTaskBoard(['add zeta zoe 2', 'add alpha al 2', 'add mid mo 10', 'add early ed 1', 'urgent', 'undo', 'urgent', 'next', 'next', 'urgent']), [
'added zeta for zoe, due on day 2',
'added alpha for al, due on day 2',
'added mid for mo, due on day 10',
'added early for ed, due on day 1',
'most urgent: early, due on day 1',
'undid early',
'most urgent: alpha, due on day 2',
'zoe starts zeta',
'al starts alpha',
'most urgent: mid, due on day 10',
]));
test('undo skips tasks that have started and stops when nothing is left', () =>
assert.deepEqual(runTaskBoard(['add x xi 3', 'add y yu 4', 'next', 'next', 'undo', 'add z zed 7', 'undo', 'undo', 'urgent']), [
'added x for xi, due on day 3',
'added y for yu, due on day 4',
'xi starts x',
'yu starts y',
'nothing to undo',
'added z for zed, due on day 7',
'undid z',
'nothing to undo',
'nothing is urgent',
]));
test('compares days as numbers, not as text', () =>
assert.deepEqual(runTaskBoard(['add big bo 10', 'add small sam 9', 'urgent']), [
'added big for bo, due on day 10',
'added small for sam, due on day 9',
'most urgent: small, due on day 9',
])); A hint
Keep the same five structures as the Python version: an array and a front index for the queue, a Map of owners, the deadlines, an array used as a stack for undo, and a Set of tasks that are gone. Python compares (day, task) tuples item by item; in JavaScript compare the days first and the names only when the days are equal.
Results of the sample tests
| Test | Result | Details |
|---|
What your code printed
The sample tests run on this device, in your browser (QuickJS): nothing is sent to mysmartcopilot.com. The first run downloads JavaScript (about 0.6 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.
Check yourself
6 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.
References
- Time complexity of operations on built-in types (Python Software Foundation)
- collections: deque objects (Python Software Foundation)
- heapq: Heap queue algorithm (Python Software Foundation)
- bisect: Array bisection algorithm (Python Software Foundation)
- graphlib: Functionality to operate with graph-like structures (Python Software Foundation)
- itertools: Functions creating iterators for efficient looping (Python Software Foundation)
- sys: recursion limit and integer string conversion limit (Python Software Foundation)
- Integer string conversion length limitation (Python Software Foundation)
- ECMAScript 2026 Language Specification (Map, Set, Array.prototype.sort, Number.MAX_SAFE_INTEGER) (Ecma International)
- Finished proposals (the ECMAScript edition each feature joined) (Ecma TC39)
- Window: structuredClone() method (MDN Web Docs (Mozilla))
- Class ArrayList (Java SE 25) (Oracle)
- Class ArrayDeque (Java SE 25) (Oracle)
- Class Stack (Java SE 25) (Oracle)
- Class HashMap (Java SE 25) (Oracle)
- Class TreeMap (Java SE 25) (Oracle)
- Class PriorityQueue (Java SE 25) (Oracle)
- Class Integer (Java SE 25) (Oracle)
- JEP 512: Compact Source Files and Instance Main Methods (OpenJDK)
- The Java Language Specification, Java SE 25: 5.1.7 Boxing Conversion (Oracle)
- The Java Language Specification, Java SE 25: 15.18.2 Additive Operators for Numeric Types (Oracle)
- C++ working draft N4950: class template stack [stack.defn] (ISO/IEC JTC1/SC22/WG21 (HTML rendering of the working draft))
- C++ working draft N4950: class template queue [queue.defn] (ISO/IEC JTC1/SC22/WG21 (HTML rendering of the working draft))
- C++ working draft N4950: sequence container requirements [sequence.reqmts] (ISO/IEC JTC1/SC22/WG21 (HTML rendering of the working draft))
- C++ working draft N4950: associative containers [associative.reqmts] (ISO/IEC JTC1/SC22/WG21 (HTML rendering of the working draft))
- C++ working draft N4950: unordered associative containers [unord.req] (ISO/IEC JTC1/SC22/WG21 (HTML rendering of the working draft))
- C++ working draft N4950: class template priority_queue [priqueue.overview] (ISO/IEC JTC1/SC22/WG21 (HTML rendering of the working draft))
- C++ working draft N4950: heap operations [alg.heap.operations] (ISO/IEC JTC1/SC22/WG21 (HTML rendering of the working draft))
- C++ working draft N4950: sorting and related operations [alg.sorting.general] (ISO/IEC JTC1/SC22/WG21 (HTML rendering of the working draft))
- C++ working draft N4950: other functions supplied by the program [res.on.functions] (ISO/IEC JTC1/SC22/WG21 (HTML rendering of the working draft))
- C++ working draft N4950: map element access [map.access] (ISO/IEC JTC1/SC22/WG21 (HTML rendering of the working draft))
- C++ working draft N4950: class template flat_map [flat.map] (ISO/IEC JTC1/SC22/WG21 (HTML rendering of the working draft))
- The Go Programming Language Specification (The Go Authors)
- Effective Go: Maps (The Go Authors)
- Go 1.27 Release Notes (The Go Authors)
- Package container/heap (The Go Authors)
- Package container/list (The Go Authors)
- Package slices (The Go Authors)
- Faster Go maps with Swiss Tables (The Go Authors)
- GATE 2027 syllabus for Computer Science and Information Technology (CS) (IIT Madras (GATE 2027 organising institute))
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress