README.md

January 9, 2026 · View on GitHub

A Typst package for solving LeetCode problems with live feedback – write your solution and instantly see test results as you type. Built-in test cases included!

Logo

Features

  • Live Feedback: Write, compile, instantly see pass/fail – like a coding notebook
  • Zero Setup: Import and start solving – built-in test cases for all problems
  • Beautiful Output: Automatic formatting with professional PDF rendering
  • Test Visualization: Side-by-side comparison of your output vs. expected results
  • 69 Problems: Curated collection of classic LeetCode problems
  • Extensible: Custom comparators, chessboard rendering, and more

Installation

#import "@preview/leetcode-livebook:0.1.0": problem, test

Quick Start

Create a new .typ file:

#import "@preview/leetcode-livebook:0.1.0": problem, test

// Display the problem
#problem(1)

// Write your solution
#let solution(nums, target) = {
  let d = (:)
  for (i, num) in nums.enumerate() {
    if str(target - num) in d {
      return (d.at(str(target - num)), i)
    }
    d.insert(str(num), i)
  }
  none
}

// Test with built-in test cases!
#test(1, solution)

If you want to display your solution, you can try

#import "@preview/leetcode-livebook:0.1.0": solve

#solve(1, ```typc
let solution(nums, target) = {
  let d = (:)
  let ans = (-1, -1)
  for (i, num) in nums.enumerate() {
    if str(target - num) in d {
      return (d.at(str(target - num)), i)
    }
    d.insert(str(num), i)
  }
  ans
}
```)
  • The main function name needs to be solution when using the solve() API.

Compile:

typst compile my-solution.typ

Or live preview:

typst watch my-solution.typ

Available Problems

IDTitleDifficulty
1Two SumEasy
2Add Two NumbersMedium
3Longest Substring Without Repeating CharactersMedium
4Median of Two Sorted ArraysHard
5Longest Palindromic SubstringMedium
6Zigzag ConversionMedium
7Reverse IntegerMedium
8String to Integer (atoi)Medium
9Palindrome NumberEasy
10Regular Expression MatchingHard
11Container With Most WaterMedium
12Integer to RomanMedium
13Roman to IntegerEasy
14Longest Common PrefixEasy
153SumMedium
163Sum ClosestMedium
17Letter Combinations of a Phone NumberMedium
184SumMedium
19Remove Nth Node From End of ListMedium
20Valid ParenthesesEasy
21Merge Two Sorted ListsEasy
22Generate ParenthesesMedium
23Merge k Sorted ListsHard
24Swap Nodes in PairsMedium
25Reverse Nodes in k-GroupHard
26Remove Duplicates from Sorted ArrayEasy
33Search in Rotated Sorted ArrayMedium
35Search Insert PositionEasy
39Combination SumMedium
42Trapping Rain WaterHard
46PermutationsMedium
48Rotate ImageMedium
49Group AnagramsMedium
50Pow(x, n)Medium
51N-QueensHard
53Maximum SubarrayMedium
54Spiral MatrixMedium
55Jump GameMedium
56Merge IntervalsMedium
62Unique PathsMedium
69Sqrt(x)Easy
70Climbing StairsEasy
72Edit DistanceMedium
76Minimum Window SubstringHard
78SubsetsMedium
94Binary Tree Inorder TraversalEasy
101Symmetric TreeEasy
104Maximum Depth of Binary TreeEasy
110Balanced Binary TreeEasy
112Path SumEasy
113Path Sum IIMedium
116Populating Next Right Pointers in Each NodeMedium
121Best Time to Buy and Sell StockEasy
144Binary Tree Preorder TraversalEasy
145Binary Tree Postorder TraversalEasy
155Min StackMedium
200Number of IslandsMedium
206Reverse Linked ListEasy
207Course ScheduleMedium
209Minimum Size Subarray SumMedium
210Course Schedule IIMedium
218The Skyline ProblemHard
289Game of LifeMedium
347Top K Frequent ElementsMedium
407Trapping Rain Water IIHard
547Number of ProvincesMedium
785Is Graph Bipartite?Medium
814Binary Tree PruningMedium
997Find the Town JudgeEasy

Multiple Problems in One File

Solve multiple problems by reusing the solution name:

#import "@preview/leetcode-livebook:0.1.0": problem, test

// Problem 1
#problem(1)
#let solution(nums, target) = { /* ... */ }
#test(1, solution)

// Problem 2
#pagebreak()
#problem(2)
#let solution(l1, l2) = { /* ... */ }
#test(2, solution)

Advanced Usage

Adding Extra Test Cases

Add your own test cases on top of built-in ones:

#import "@preview/leetcode-livebook:0.1.0": problem, test

#problem(1)
#let solution(nums, target) = { /* ... */ }

// Built-in cases + your extra cases
#test(1, solution, extra-cases: (
  (nums: (99, 1), target: 100),
  (nums: range(1000), target: 999),
))

Using Only Custom Test Cases

Override built-in cases completely:

#test(1, solution,
  extra-cases: (
    (nums: (1, 2, 3), target: 5),
  ),
  default-cases: false)

Unordered Output

For problems with "return answer in any order":

#import "@preview/leetcode-livebook:0.1.0": problem, test

#problem(15)  // 3Sum
#let solution(nums) = { /* ... */ }

// Metadata is handled automatically!
#test(15, solution)  // Uses unordered-compare automatically

Chessboard Rendering

For problems like N-Queens:

#import "@preview/leetcode-livebook:0.1.0": problem, test

#problem(51)
#let solution(n) = { /* ... */ }

// Chessboard rendering enabled automatically!
#test(51, solution)

Viewing Reference Solutions

Stuck on a problem? View the reference solution code:

#import "@preview/leetcode-livebook:0.1.0": problem, answer

#problem(1)
// ... tried but couldn't solve it ...

// Display the reference solution code
#answer(1)

Manual Reference Access

For advanced control:

#import "@preview/leetcode-livebook:0.1.0": problem, get-test-cases, get-problem-path

// Get built-in test cases
#let cases = get-test-cases(1)

// Get problem directory path
#let path = get-problem-path(1)
#import (path + "solution.typ"): solution

API Reference

Main Functions

FunctionDescription
problem(id)Display problem with difficulty badge
test(id, fn, ...)Test solution with built-in cases
answer(id)Display reference solution code
solve(id, code-block)Display code and test in one call
get-test-cases(id)Get built-in test cases as array
get-problem-path(id)Get problem directory path
get-problem-info(id)Get metadata (title, difficulty, labels)

Data Structure Functions

FunctionDescription
linkedlist(array)Create linked list from array
ll-val(list, id)Get value at node ID
ll-next(list, id)Get next node ID
ll-values(list)Get all values as array
binarytree(array)Create binary tree from level-order array

Utility Functions

FunctionDescription
display(value)Format value for output
fill(value, n)Create array with n copies
chessboard(board)Render chessboard visualization
unordered-compare(a, b)Compare ignoring order
float-compare(a, b)Compare floats with tolerance
testcases(fn, ref, cases, ...)Manual test comparison

Examples

Check out template/main.typ for a starter template that demonstrates the practice workbook mode with the solve() API.

Architecture

Each problem is organized as:

problems/XXXX/
├── problem.toml       # Metadata (title, difficulty, labels)
├── description.typ    # Problem statement
├── solution.typ       # Reference solution
└── testcases.typ      # Test cases (pure data)

problem.toml structure:

title = "Two Sum"
difficulty = "easy"
labels = ["array", "hash-table"]

# Optional: for special handling
# comparator = "unordered-compare"
# render-chessboard = true

Testcases can use helper functions:

// testcases.typ
#import "../../helpers.typ": linkedlist

#let cases = (
  (head: linkedlist((1, 2, 3)), n: 2),
)

This design ensures:

  • High cohesion: All files for a problem are together
  • Built-in tests: No need to write test cases
  • Metadata support: Difficulty badges, comparators, and rendering options
  • Helper access: Testcases can use linkedlist, fill, etc.

Tips

Linked Lists

#import "@preview/leetcode-livebook:0.1.0": linkedlist, ll-values

#let list = linkedlist((1, 2, 3))
#let values = ll-values(list)  // (1, 2, 3)

Binary Trees

#import "@preview/leetcode-livebook:0.1.0": binarytree

// Level-order array: [1, 2, 3, null, 4]
#let tree = binarytree((1, 2, 3, none, 4))

Live Preview

Use Typst's watch mode or Tinymist for instant feedback.

Adding Your Own Test Cases

Mix built-in and custom cases:

#test(1, solution, extra-cases: (
  (nums: (0, 0), target: 0),
  (nums: range(100), target: 99),
))

Why Typst?

This project explores Typst as a functional programming language for algorithms, demonstrating:

  • Expressive syntax for pattern matching and FP
  • Beautiful output with minimal effort
  • Rapid feedback with live preview
  • Creative constraints that enhance problem-solving

Contributing

Maintained at github.com/lucifer1004/leetcode.typ.

To add problems, use:

python3 scripts/create.py <problem-id>

License

MIT License - see LICENSE file for details.

Disclaimer

LeetCode problem descriptions are the property of © LeetCode. This package is for personal learning and educational purposes only. For official problem statements, please visit leetcode.com.