Python challenges
Small problems to practise on, from easy to hard. Your code is checked automatically in the browser. Hints are there when you are stuck, and a reference solution when you are done. New to Python? Do the first few Python lessons first.
Basics
Loops, strings and conditions. The first four Python lessons cover everything you need.
0 of 8 solvedSum of digits
Write digit_sum(n) that returns the sum of the decimal digits of a non-negative integer.
Reverse the words
Write reverse_words(sentence) that returns the sentence with the order of the words reversed. Words are separated by single spaces; keep each word intact.
Count the vowels
Write count_vowels(text) that returns how many vowels (a, e, i, o, u — either case) the text contains.
Largest, by hand
Write largest(numbers) that returns the biggest number in a non-empty list — without using the built-in max() or sorted().
Temperature table
Print a conversion table from 0 °C to 100 °C in steps of 20. Each line should look like 20C = 68.0F — Celsius, then Fahrenheit with one decimal place.
Factorial
Write factorial(n) that returns n! — the product of every integer from 1 to n. factorial(0) is 1. Solve it with a loop or with recursion, your choice.
Leap years
Write is_leap(year). A year is a leap year if it is divisible by 4, except centuries, which are leap years only when divisible by 400. So 2000 and 2024 are leap years; 1900 and 2023 are not.
Palindromic numbers
Write is_palindrome_number(n) that returns True if the integer reads the same backwards. Negative numbers are never palindromes.
Core
Dictionaries, sorting, recursion and classic algorithms. Expect to think for a few minutes before typing.
0 of 11 solvedCaesar cipher
Write caesar(text, shift) that shifts every letter by shift positions in the alphabet, wrapping around from z to a. Preserve case; leave spaces, digits and punctuation untouched.
Anagram check
Write are_anagrams(a, b) that returns True when the two strings use exactly the same letters, ignoring case and spaces.
Most common words
Write top_words(text, n) that returns the n most frequent words as a list of (word, count) tuples, most frequent first. Compare words case-insensitively and strip punctuation. Break ties alphabetically.
Sieve of Eratosthenes
Write primes_up_to(limit) that returns a list of all prime numbers ≤ limit, using the sieve: mark multiples of each prime as composite rather than testing each number individually.
Two sum
Write two_sum(numbers, target) that returns the indices of the two numbers that add up to target, as a tuple (i, j) with i < j. Assume exactly one answer exists. Aim for a single pass using a dictionary.
Run-length encoding
Write encode(text) that compresses runs of repeated characters into the character followed by its count, and decode(encoded) that reverses it. Assume the input contains no digits.
Transpose a matrix
Write transpose(matrix) that flips a list-of-lists over its diagonal: rows become columns. The matrix may be non-square.
Roman numerals
Write to_roman(n) for 1 ≤ n ≤ 3999. Remember the subtractive forms: 4 is IV, 9 is IX, 40 is XL, 90 is XC, 400 is CD, 900 is CM.
Binary search
Write binary_search(sorted_list, target) that returns the index of target, or -1 if absent. Halve the search range each step; do not scan linearly.
Balanced brackets
Write is_balanced(s) that returns True if every opening bracket ( [ { is closed by the matching type in the correct order. Ignore any other characters.
Flatten anything
Write flatten(nested) that turns arbitrarily nested lists into one flat list, preserving order. Non-list items are kept as they are.
Intermediate
Data structures, parsers and decorators. Each one is a small piece of real software.
0 of 7 solvedGroup anagrams
Write group_anagrams(words) that groups words which are anagrams of each other. Return a list of groups (each a list, in original order), with the groups ordered by their first appearance.
Merge intervals
Write merge_intervals(intervals), where each interval is a [start, end] list. Merge every pair that overlaps or touches and return the result sorted by start.
Build an LRU cache
Implement LRUCache(capacity) with get(key) and put(key, value). get returns the value or -1 if missing, and marks the key as recently used. put inserts or updates; when the cache is over capacity, evict the least recently used key. Python dicts remember insertion order, which is all you need.
Spiral order
Write spiral(matrix) that returns the elements of a 2-D list in clockwise spiral order, starting from the top-left corner.
Write memoize
Write a decorator memoize that caches results by positional arguments, and exposes the number of cache hits as func.hits. Then use it on the slow recursive count_paths(rows, cols) so that count_paths(16, 16) returns instantly.
Expression calculator
Write evaluate(expr) that computes an arithmetic expression given as a string, supporting + - * /, parentheses, decimal numbers and the usual precedence. Do not use eval().
Inventory report
Given a list of Item dataclasses, write report(items) that returns a multi-line string: one line per item as NAME padded to 12 chars, quantity right-aligned in 4, and total value (qty × price) right-aligned in 9 with two decimals; then a final line TOTAL followed by the grand total in the same 9-wide column. Sort items by name.
Advanced
Simulations, graphs, tries and parsers. Sketch a plan on paper before you start.
0 of 8 solvedConway's Game of Life
Write step(grid) that returns the next generation of a Game of Life grid (a list of lists of 0/1). A live cell with two or three live neighbours survives; a dead cell with exactly three comes alive; everything else dies. Cells outside the grid count as dead.
Topological sort
Write build_order(deps) where deps maps each task to the list of tasks it depends on. Return a list containing every task exactly once, such that each task comes after all of its dependencies. Raise ValueError if there is a cycle. When several orders are valid, any one is accepted.
Trie autocomplete
Implement Trie with insert(word), contains(word) and starts_with(prefix), which returns every inserted word beginning with the prefix in alphabetical order. Store the words in a tree of dictionaries, one level per character.
Word wrap
Write wrap(text, width) that breaks text into lines no longer than width characters, breaking only at spaces, greedily fitting as many words per line as possible. Words longer than width go on their own line unbroken. Return the list of lines.
Flatten JSON
Write flatten_json(obj) that turns nested dicts and lists into a single-level dict whose keys are dotted paths. List elements use their index as a key segment. Scalars keep their values.
Sudoku validator
Write is_valid_sudoku(board) for a 9×9 grid of integers where 0 means empty. Return True if no row, column or 3×3 box contains a repeated digit 1–9. Empty cells never conflict.
Dijkstra's shortest path
Write shortest_path(graph, start, end) for a weighted graph given as {node: {neighbour: weight}}. Return (distance, path) with the path as a list of nodes, or (None, []) if end is unreachable. Use heapq for the priority queue.
Mini Markdown
Write to_html(md) that converts a tiny Markdown subset: lines starting with # or ## become <h1>/<h2>; lines starting with "- " form a <ul> of <li>; any other non-empty line is a <p>. Inline, **bold** becomes <strong> and *italic* becomes <em>. Blank lines separate blocks. Return the HTML lines joined with newlines.