Python course menu
Python Coding Challenges With Solutions (Interview Practice)
Ten classic Python coding interview challenges with hints and tested solutions: two sum, anagrams, first unique character, valid brackets, merging sorted lists, binary search, maximum subarray, grouping anagrams, string compression and list rotation.
On this page
- Challenge 1: Two Sum
- Challenge 2: Anagram check
- Challenge 3: First unique character
- Challenge 4: Valid brackets
- Challenge 5: Merge two sorted lists
- Challenge 6: Binary search
- Challenge 7: Maximum subarray sum
- Challenge 8: Group anagrams
- Challenge 9: String compression
- Challenge 10: Rotate a list
- How to approach any coding challenge
These are classic problems from coding interviews and online assessments. Each one teaches a reusable technique, such as hashing, stacks, two pointers or running totals. Try each for at least 10 minutes before opening the hint, and state the time complexity of your answer, because interviewers always ask.
Challenge 1: Two Sum#
Two Sum
Return the indexes of the two numbers in a list that add up to a target, or None if there are none. Example: [2, 7, 11, 15], target 9 → [0, 1].
Show hint
For each number, the partner you need is target - n. A dictionary of values you have already seen answers "have I seen it?" instantly.
Show solution
def two_sum(nums, target):
seen = {} # value -> index
for i, n in enumerate(nums):
if target - n in seen:
return [seen[target - n], i]
seen[n] = i
return None
print(two_sum([2, 7, 11, 15], 9), two_sum([3, 2, 4], 6), two_sum([1, 2], 10))[0, 1] [1, 2] NoneO(n) time, O(n) memory. The brute-force nested loop is O(n²).
Challenge 2: Anagram check#
Anagrams
Return True if two strings are anagrams (same letters, same counts), ignoring spaces and case.
Show hint
Count the letters of each string with Counter, or compare the sorted letters.
Show solution
from collections import Counter
def is_anagram(a, b):
clean = lambda s: Counter(s.replace(" ", "").lower())
return clean(a) == clean(b)
print(is_anagram("Listen", "Silent"),
is_anagram("Dormitory", "dirty room"),
is_anagram("abc", "abd"))True True FalseO(n) with Counter; O(n log n) with sorted().
Challenge 3: First unique character#
First unique character
Return the first character that appears exactly once in a string, or None.
Show hint
Count first, then scan the string a second time in order.
Show solution
from collections import Counter
def first_unique(s):
counts = Counter(s)
for ch in s:
if counts[ch] == 1:
return ch
return None
print(first_unique("swiss"), first_unique("aabb"), first_unique("leetcode"))w None lTwo passes, O(n) time.
Challenge 4: Valid brackets#
Valid brackets
Return True if every bracket in a string like "([]{})" is closed by the right type, in the right order.
Show hint
Use a stack: push opening brackets; on a closing bracket, the top of the stack must be its matching opener.
Show solution
def is_valid(brackets):
pairs = {")": "(", "]": "[", "}": "{"}
stack = []
for ch in brackets:
if ch in "([{":
stack.append(ch)
elif ch in pairs:
if not stack or stack.pop() != pairs[ch]:
return False
return not stack
print(is_valid("([]{})"), is_valid("([)]"), is_valid("(("), is_valid(""))True False False True"((" fails because the stack is not empty at the end. O(n).
Challenge 5: Merge two sorted lists#
Merge sorted lists
Merge two sorted lists into one sorted list without calling sorted().
Show hint
Two pointers: repeatedly take the smaller front element, then append whatever remains.
Show solution
def merge_sorted(a, b):
i = j = 0
out = []
while i < len(a) and j < len(b):
if a[i] <= b[j]:
out.append(a[i]); i += 1
else:
out.append(b[j]); j += 1
return out + a[i:] + b[j:]
print(merge_sorted([1, 4, 7], [2, 3, 8, 9]))[1, 2, 3, 4, 7, 8, 9]O(n + m). This is the core step of merge sort.
Challenge 6: Binary search#
Binary search
Find the index of a target in a sorted list in O(log n) time, or return -1.
Show hint
Keep a lo and hi range. Check the middle; discard the half that cannot contain the target.
Show solution
def binary_search(items, target):
lo, hi = 0, len(items) - 1
while lo <= hi:
mid = (lo + hi) // 2
if items[mid] == target:
return mid
if items[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return -1
data = [3, 8, 15, 23, 42, 57, 91]
print(binary_search(data, 42), binary_search(data, 5))4 -1Each step halves the range: about 20 steps for a million items. The standard library's bisect module provides this too.
Challenge 7: Maximum subarray sum#
Maximum subarray
Find the largest sum of any contiguous part of a list. Example: [-2, 1, -3, 4, -1, 2, 1, -5, 4] → 6 (from [4, -1, 2, 1]).
Show hint
Kadane's algorithm: at each number, either extend the current run or start a new one, whichever is larger. Track the best seen.
Show solution
def max_subarray(nums):
best = cur = nums[0]
for n in nums[1:]:
cur = max(n, cur + n)
best = max(best, cur)
return best
print(max_subarray([-2, 1, -3, 4, -1, 2, 1, -5, 4]), max_subarray([-3, -1, -2]))6 -1Starting from nums[0] (not 0) handles all-negative lists correctly. O(n).
Challenge 8: Group anagrams#
Group anagrams
Group words that are anagrams of each other: ["eat", "tea", "tan", "ate", "nat", "bat"].
Show hint
Anagrams have the same sorted letters. Use that as a dictionary key.
Show solution
from collections import defaultdict
def group_anagrams(words):
groups = defaultdict(list)
for w in words:
groups["".join(sorted(w))].append(w)
return list(groups.values())
print(group_anagrams(["eat", "tea", "tan", "ate", "nat", "bat"]))[['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']]O(n · k log k), where k is the word length.
Challenge 9: String compression#
String compression
Compress runs of repeated characters: "aaabccdddd" → "a3b1c2d4". An empty string stays empty.
Show hint
Walk through pairs of neighbouring characters with zip(s, s[1:]), counting until the character changes.
Show solution
def compress(s):
if not s:
return ""
out = []
count = 1
for prev, ch in zip(s, s[1:]):
if ch == prev:
count += 1
else:
out.append(f"{prev}{count}")
count = 1
out.append(f"{s[-1]}{count}")
return "".join(out)
print(compress("aaabccdddd"), compress("abc"), repr(compress("")))a3b1c2d4 a1b1c1 ''Building a list and joining once is faster than repeated string +=.
Challenge 10: Rotate a list#
Rotate a list
Rotate a list to the right by k steps: [1, 2, 3, 4, 5], k = 2 → [4, 5, 1, 2, 3]. k may be larger than the list.
Show hint
Reduce k with k % len(nums), then join two slices.
Show solution
def rotate(nums, k):
k %= len(nums)
return nums[-k:] + nums[:-k] if k else nums[:]
print(rotate([1, 2, 3, 4, 5], 2), rotate([1, 2, 3], 4), rotate([1, 2], 0))[4, 5, 1, 2, 3] [3, 1, 2] [1, 2]The if k guard matters: with k = 0, nums[-0:] is the whole list, which would duplicate it.
How to approach any coding challenge#
- Clarify: input sizes, duplicates, negative numbers, empty input.
- Start simple: describe a brute-force solution and its complexity.
- Improve: can a dictionary, set, stack, sorting, or two pointers remove a nested loop?
- Code cleanly: good names, small helper functions.
- Test out loud with a normal case and an edge case.
More practice: the Python practice sets and the programming fundamentals questions.
Finished this lesson?