Skip to main content
Editor

50 Python Practice Problems with Instant Answer Checking (Beginner to Advanced)

Beginner240 min50 exercises950 XP
0/50 exercises

Fifty problems, each with a code editor and real tests. Write your solution, press Check, and see exactly which cases pass. Stuck? Hints reveal one at a time, and the solution unlocks once you have checked at least once. Your code and progress are saved in this browser.

They are grouped in three tiers. Beginner (1-20): strings, numbers, lists, dictionaries and your first error handling. Intermediate (21-35): generators, classic algorithms, regular expressions and a first class. Advanced (36-50): the interview staples (hash maps, sliding windows, dynamic programming, graphs) plus decorators, context managers, dataclasses and pandas.

Beginner Problems (1-20)

Strings, numbers, lists and dictionaries. If you are new to Python, go in order. If not, use them as a warm-up and move fast.

Problem 1: FizzBuzz

Write fizzbuzz(n) that returns a list of strings for the numbers 1 to n: "Fizz" for multiples of 3, "Buzz" for multiples of 5, "FizzBuzz" for multiples of both, and the number itself (as a string) otherwise.

fizzbuzz(5)  ->  ["1", "2", "Fizz", "4", "Buzz"]
def fizzbuzz(n):
# Return a list of strings for 1..n
pass
Solution unlocks after your first Check

Problem 2: Reverse the Words

Write reverse_words(sentence) that returns the words in reverse order, separated by single spaces. Extra spaces anywhere in the input should not matter.

reverse_words("hello big world")  ->  "world big hello"
def reverse_words(sentence):
pass
Solution unlocks after your first Check

Problem 3: Count the Vowels

Write count_vowels(text) that returns how many vowels (a, e, i, o, u) the text contains, ignoring case.

count_vowels("Hello World")  ->  3
def count_vowels(text):
pass
Solution unlocks after your first Check

Problem 4: Palindrome Check

Write is_palindrome(text) that returns True if the text reads the same forwards and backwards, ignoring case, spaces and punctuation.

is_palindrome("A man, a plan, a canal: Panama")  ->  True
def is_palindrome(text):
pass
Solution unlocks after your first Check

Problem 5: Sum of Digits

Write digit_sum(n) that returns the sum of the digits of the integer n. It must work for negative numbers too (ignore the minus sign).

digit_sum(1234)  ->  10
digit_sum(-58)   ->  13
def digit_sum(n):
pass
Solution unlocks after your first Check

Problem 6: Largest Number Without max()

Write largest(numbers) that returns the largest number in the list without using `max()`. For an empty list return None.

largest([3, 9, 2])  ->  9
largest([])         ->  None
def largest(numbers):
pass
Solution unlocks after your first Check

Problem 7: Remove Duplicates, Keep the Order

Write dedupe(items) that returns a new list without duplicates, keeping the first occurrence of each item in its original position.

dedupe([3, 1, 3, 2, 1])  ->  [3, 1, 2]
def dedupe(items):
pass
Solution unlocks after your first Check

Problem 8: Second Largest Value

Write second_largest(numbers) that returns the second largest distinct value. If there is no such value (fewer than two distinct numbers), return None.

second_largest([4, 1, 4, 3])  ->  3
second_largest([7, 7])        ->  None
def second_largest(numbers):
pass
Solution unlocks after your first Check

Problem 9: Most Common Character

Write most_common_char(text) that returns the character that appears most often, ignoring spaces and case. If there is a tie, return the one that appears first in the text.

most_common_char("Mississippi")  ->  "i"
def most_common_char(text):
pass
Solution unlocks after your first Check

Problem 10: Are They Anagrams?

Write is_anagram(a, b) that returns True if the two strings use exactly the same letters the same number of times, ignoring case and spaces.

is_anagram("Listen", "Silent")  ->  True
def is_anagram(a, b):
pass
Solution unlocks after your first Check

Problem 11: Factorial, With a Proper Error

Write factorial(n) that returns n! using a loop (no math.factorial). factorial(0) is 1. For a negative n, raise a `ValueError`.

factorial(5)   ->  120
factorial(-1)  ->  ValueError
def factorial(n):
pass
Solution unlocks after your first Check

Problem 12: Is It Prime?

Write is_prime(n) that returns True if n is a prime number. Numbers below 2 are not prime. Only test divisors up to the square root of n.

def is_prime(n):
pass
Solution unlocks after your first Check

Problem 13: Letter Grade

Write letter_grade(score) for a score from 0 to 100: 90 and above is "A", 80+ "B", 70+ "C", 60+ "D", below 60 "F". A score outside 0-100 must raise `ValueError`.

def letter_grade(score):
pass
Solution unlocks after your first Check

Problem 14: Title Case Without .title()

Write title_case(text) that capitalises the first letter of every word and lower-cases the rest, without using str.title() or str.capitalize(). Words are separated by single spaces.

title_case("hELLO wORLD")  ->  "Hello World"
def title_case(text):
pass
Solution unlocks after your first Check

Problem 15: Common Elements

Write common(a, b) that returns the items found in both lists, in the order they appear in a, without duplicates.

common([1, 2, 3, 2, 4], [4, 2, 9])  ->  [2, 4]
def common(a, b):
pass
Solution unlocks after your first Check

Problem 16: Flatten a List of Lists

Write flatten(rows) that turns a list of lists into one list, using a list comprehension.

flatten([[1, 2], [3], [], [4, 5]])  ->  [1, 2, 3, 4, 5]
def flatten(rows):
pass
Solution unlocks after your first Check

Problem 17: Merge Two Inventories

Two shops store stock as dictionaries of item -> count. Write merge_inventory(a, b) that returns a new dictionary with the counts added together. Do not change the inputs.

merge_inventory({"apple": 3, "pear": 1}, {"apple": 2, "fig": 5})
->  {"apple": 5, "pear": 1, "fig": 5}
def merge_inventory(a, b):
pass
Solution unlocks after your first Check

Problem 18: Invert a Dictionary

Write invert(d) that swaps keys and values. Several keys can share a value, so each value maps to a list of keys, in their original order.

invert({"ann": "red", "bob": "blue", "cy": "red"})
->  {"red": ["ann", "cy"], "blue": ["bob"]}
def invert(d):
pass
Solution unlocks after your first Check

Problem 19: Password Strength Check

Write password_problems(pw) that returns a list of the rules the password breaks, in this order:

1. "too short" if it has fewer than 8 characters

2. "no digit"

3. "no uppercase"

4. "no lowercase"

A strong password returns [].

def password_problems(pw):
pass
Solution unlocks after your first Check

Problem 20: Average of Messy Input

Data from a form arrives as strings, and some are junk. Write safe_average(values) that converts each value to a float, skips anything that cannot be converted, and returns the average rounded to 2 decimals. If nothing is valid, return None.

safe_average(["4", "x", "5.5", ""])  ->  4.75
def safe_average(values):
pass
Solution unlocks after your first Check

Intermediate Problems (21-35)

Generators, the classic algorithms every programmer should be able to write from memory, regular expressions, and your first class with real rules.

Problem 21: Fibonacci Generator

Write a generator fibonacci() that yields the Fibonacci numbers forever: 0, 1, 1, 2, 3, 5, ... The tests take as many as they need with itertools.islice.

def fibonacci():
# use yield
pass
Solution unlocks after your first Check

Problem 22: Sieve of Eratosthenes

Write primes_up_to(n) that returns all primes up to and including n using the Sieve of Eratosthenes: start with everything marked prime, then cross out the multiples of each prime.

def primes_up_to(n):
pass
Solution unlocks after your first Check

Problem 23: Caesar Cipher

Write caesar(text, shift) that shifts every letter by shift places, wrapping around the alphabet. Keep the case, leave everything that is not a letter unchanged, and allow negative shifts (which decode).

caesar("Hello, World!", 3)  ->  "Khoor, Zruog!"
def caesar(text, shift):
pass
Solution unlocks after your first Check

Problem 24: Top Words in a Text

Write top_words(text, n) that returns the n most common words as (word, count) tuples. Ignore case and punctuation; a word is a run of letters (and apostrophes). Ties keep the order of first appearance.

top_words("The cat and the hat. The END!", 2)  ->  [("the", 3), ("cat", 1)]
def top_words(text, n):
pass
Solution unlocks after your first Check

Problem 25: Group the Anagrams

Write group_anagrams(words) that groups words that are anagrams of each other. Return a list of groups; groups appear in the order their first word appears, and words keep their original order inside each group.

group_anagrams(["eat", "tea", "tan", "ate", "nat", "bat"])
->  [["eat", "tea", "ate"], ["tan", "nat"], ["bat"]]
def group_anagrams(words):
pass
Solution unlocks after your first Check

Problem 26: Balanced Brackets

Write is_balanced(s) that returns True if every (, [ and { is closed by the matching bracket in the right order. Other characters are ignored.

is_balanced("{[()()]}")  ->  True
is_balanced("([)]")      ->  False
def is_balanced(s):
pass
Solution unlocks after your first Check

Problem 27: Run-Length Encoding

Write rle(text) that compresses runs of the same character into the character followed by its count.

rle("aaabccdddd")  ->  "a3b1c2d4"
def rle(text):
pass
Solution unlocks after your first Check

Problem 28: Binary Search

Write binary_search(items, target) for a sorted list. Return the index of target, or -1 if it is not there. Do not use .index() or the bisect module.

def binary_search(items, target):
pass
Solution unlocks after your first Check

Problem 29: Merge Two Sorted Lists

Write merge_sorted(a, b) that merges two already-sorted lists into one sorted list in a single pass. Do not call sort() or sorted().

def merge_sorted(a, b):
pass
Solution unlocks after your first Check

Problem 30: Rotate a List

Write rotate(items, k) that rotates the list to the right by k places and returns a new list. k can be larger than the list.

rotate([1, 2, 3, 4, 5], 2)  ->  [4, 5, 1, 2, 3]
def rotate(items, k):
pass
Solution unlocks after your first Check

Problem 31: Deep Flatten

Write deep_flatten(data) that flattens lists nested to any depth into one flat list.

deep_flatten([1, [2, [3, [4]], 5]])  ->  [1, 2, 3, 4, 5]
def deep_flatten(data):
pass
Solution unlocks after your first Check

Problem 32: Roman Numerals

Write to_roman(n) that converts an integer from 1 to 3999 into Roman numerals, including the subtractive forms like IV (4), IX (9), XL (40) and CM (900).

def to_roman(n):
pass
Solution unlocks after your first Check

Problem 33: Longest Common Prefix

Write common_prefix(words) that returns the longest prefix shared by every word in the list (an empty string if there is none, or if the list is empty).

common_prefix(["flower", "flow", "flight"])  ->  "fl"
def common_prefix(words):
pass
Solution unlocks after your first Check

Problem 34: Parse a Log Line With Regex

Server logs look like 2026-10-02 14:03:55 [ERROR] Disk almost full. Write parse_log(line) that returns a dict with "date", "time", "level" and "message", or None if the line does not match. Levels are upper-case words.

{"date": "2026-10-02", "time": "14:03:55", "level": "ERROR", "message": "Disk almost full"}
import re
def parse_log(line):
pass
Solution unlocks after your first Check

Problem 35: A Bank Account Class

Write a class BankAccount:

  • BankAccount(owner, balance=0)
  • deposit(amount) and withdraw(amount). Both raise ValueError for amounts of 0 or less, and withdraw raises ValueError if there is not enough money.
  • a read-only balance property
  • history is a list of ("deposit", amount) / ("withdraw", amount) tuples for successful operations
  • class BankAccount:
    def __init__(self, owner, balance=0):
    pass
    Solution unlocks after your first Check

    Advanced Problems (36-50)

    The interview staples (hash maps, sliding windows, dynamic programming, graphs), then the Python features that separate fluent code from working code: decorators, context managers, dataclasses and pandas.

    Problem 36: Two Sum

    Write two_sum(nums, target) that returns the indexes (i, j) with i < j of the two numbers that add up to target, or None if there are none. Do it in one pass (O(n)), not with two nested loops.

    two_sum([2, 7, 11, 15], 9)  ->  (0, 1)
    def two_sum(nums, target):
    pass
    Solution unlocks after your first Check

    Problem 37: Longest Substring Without Repeats

    Write longest_unique(s) that returns the length of the longest substring with no repeated characters.

    longest_unique("abcabcbb")  ->  3   ("abc")
    longest_unique("pwwkew")    ->  3   ("wke")
    def longest_unique(s):
    pass
    Solution unlocks after your first Check

    Problem 38: Merge Overlapping Intervals

    Meetings are [start, end] pairs in any order. Write merge_intervals(intervals) that merges every overlapping (or touching) pair and returns the result sorted by start.

    merge_intervals([[8, 10], [1, 3], [2, 6], [15, 18]])
    ->  [[1, 6], [8, 10], [15, 18]]
    def merge_intervals(intervals):
    pass
    Solution unlocks after your first Check

    Problem 39: Top K Frequent Elements

    Write top_k(nums, k) that returns the k most frequent values, most frequent first. Ties go to the value that appears first in nums.

    top_k([1, 1, 1, 2, 2, 3], 2)  ->  [1, 2]
    def top_k(nums, k):
    pass
    Solution unlocks after your first Check

    Problem 40: Maximum Subarray (Kadane)

    Write max_subarray(nums) that returns the largest sum of any non-empty run of consecutive numbers, in O(n).

    max_subarray([-2, 1, -3, 4, -1, 2, 1, -5, 4])  ->  6   ([4, -1, 2, 1])
    def max_subarray(nums):
    pass
    Solution unlocks after your first Check

    Problem 41: Coin Change (Dynamic Programming)

    Write min_coins(coins, amount) that returns the fewest coins that add up to amount (each coin can be used any number of times), or -1 if it is impossible.

    min_coins([1, 2, 5], 11)  ->  3   (5 + 5 + 1)
    def min_coins(coins, amount):
    pass
    Solution unlocks after your first Check

    Problem 42: Longest Increasing Subsequence

    Write lis_length(nums) that returns the length of the longest strictly increasing subsequence (the items do not need to be next to each other).

    lis_length([10, 9, 2, 5, 3, 7, 101, 18])  ->  4   (2, 3, 7, 18)
    def lis_length(nums):
    pass
    Solution unlocks after your first Check

    Problem 43: Shortest Path in a Graph (BFS)

    A graph is a dict mapping each node to a list of neighbours. Write shortest_path(graph, start, goal) that returns the shortest path as a list of nodes, or None if goal cannot be reached. Explore neighbours in the order they are listed.

    from collections import deque
    def shortest_path(graph, start, goal):
    pass
    Solution unlocks after your first Check

    Problem 44: LRU Cache

    Write a class LRUCache(capacity) with get(key) (returns the value, or -1 if missing) and put(key, value). When it is full, put evicts the least recently used key. Reading a key with get counts as using it. Both operations must be O(1).

    from collections import OrderedDict
    class LRUCache:
    def __init__(self, capacity):
    pass
    Solution unlocks after your first Check

    Problem 45: Trie for Autocomplete

    Write a class Trie with insert(word), search(word) (True only for whole words that were inserted) and starts_with(prefix), which returns a sorted list of all inserted words that begin with prefix.

    class Trie:
    def __init__(self):
    pass
    Solution unlocks after your first Check

    Problem 46: Write a Memoize Decorator

    Write a decorator memoize that caches a function's results by its positional arguments, so repeated calls return instantly. The decorated function must keep its original __name__. (Do not use functools.lru_cache or functools.cache.)

    import functools
    def memoize(func):
    pass
    Solution unlocks after your first Check

    Problem 47: A Retry Decorator With Arguments

    Write retry(times, exceptions=(Exception,)), a decorator factory. The decorated function is called up to times times; if it raises one of exceptions, try again. If the last attempt still fails, re-raise that error. Other exception types must not be retried.

    @retry(times=3, exceptions=(ConnectionError,))
    def fetch(): ...
    import functools
    def retry(times, exceptions=(Exception,)):
    pass
    Solution unlocks after your first Check

    Problem 48: A Context Manager That Cleans Up

    Write a context manager temporarily(obj, name, value) that sets the attribute obj.name = value inside a with block and always restores the original value afterwards, even if the block raises an error.

    with temporarily(settings, "debug", True):
        ...   # settings.debug is True here
    # settings.debug is back to what it was
    from contextlib import contextmanager
    @contextmanager
    def temporarily(obj, name, value):
    pass
    Solution unlocks after your first Check

    Problem 49: Revenue by Region With pandas

    Each row of a sales DataFrame has region, price and qty. Write revenue_by_region(df) that returns a Series of total revenue (price * qty) per region, sorted from highest to lowest and rounded to 2 decimals. Do not modify df.

    import pandas as pd
    def revenue_by_region(df):
    pass
    Solution unlocks after your first Check

    Problem 50: Leaderboard With a Dataclass

    Create a dataclass Player with name: str and score: int. Then write leaderboard(players) that returns the names ranked by score (highest first), with ties ordered alphabetically by name.

    from dataclasses import dataclass
    # Player dataclass here
    def leaderboard(players):
    pass
    Solution unlocks after your first Check

    What to Do Next

    Each solved problem has a Save to GitHub button: it adds your solution to your own python-practice repository, with a progress table and a badge for your GitHub profile. Then test yourself under exam conditions with the section quizzes and earn a certificate, or follow the Python roadmap for the topics you found hardest.

    Related Tutorials

    Was this tutorial helpful?