Python Challenges for Every Career Stage
Navigating a career in software development means constantly growing your skills. Whether you’re a junior developer writing your first scripts, a mid-level engineer building complex applications, or a senior dev architecting systems, targeted Python practice is key.
That’s exactly what this page is for. We’ve organized Python coding challenges specifically for Junior, Mid-Level, and Senior developers for each level. It’s the perfect way to prepare for your next career move or to find the perfect Python programmer for your team.
Jump to Your Level
| Junior Developer | Mid-Level Developer | Senior Developer |
Junior Developer Challenges
1. Reverse a String
Tests basic string slicing.
def reverse_string(s):
return s[::-1]2. Check for Palindrome
A simple test of string comparison and slicing.
def is_palindrome(s):
return s == s[::-1]3. FizzBuzz
The quintessential test of basic loops and conditionals.
def fizz_buzz(n):
for i in range(1, n + 1):
if i % 15 == 0:
print("FizzBuzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)4. Find Maximum in List
A fundamental list operation.
def find_max(numbers):
return max(numbers)5. Sum of a List
A simple loop to practice accumulation.
def sum_list(numbers):
return sum(numbers)6. Count Vowels in a String
Good for practicing character-by-character string processing.
def count_vowels(s):
vowels = "aeiou"
return sum(1 for char in s.lower() if char in vowels)7. Factorial of a Number
A classic introduction to recursion.
def factorial(n):
if n <= 1:
return 1
return n * factorial(n - 1)8. Find an Element in a List
Checks for understanding of basic search logic.
def find_element(elements, target):
for i, element in enumerate(elements):
if element == target:
return i
return -19. Check if Number is Even or Odd
Tests the most basic conditional logic.
def is_even(num):
return num % 2 == 010. Concatenate Two Lists
A problem for understanding basic list operations.
def concat_lists(list_a, list_b):
return list_a + list_bMid-Level Developer Challenges
1. Two Sum
The classic interview question to test knowledge of dictionaries.
def two_sum(nums, target):
seen = {}
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i2. Valid Parentheses
A perfect problem for demonstrating the use of a stack (via a list).
def is_valid_parentheses(s):
stack = []
mapping = {")": "(", "}": "{", "]": "["}
for char in s:
if char in mapping:
top_element = stack.pop() if stack else '#'
if mapping[char] != top_element:
return False
else:
stack.append(char)
return not stack3. Binary Search
Tests understanding of efficient search algorithms in a sorted list.
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -14. Group Anagrams
Requires creative use of dictionaries and sorting to group words.
from collections import defaultdict
def group_anagrams(strs):
anagrams = defaultdict(list)
for s in strs:
anagrams[tuple(sorted(s))].append(s)
return list(anagrams.values())5. Longest Substring Without Repeating Characters
A sliding window problem that tests dynamic substring analysis.
def length_of_longest_substring(s):
char_set = set()
left = 0
max_len = 0
for right, char in enumerate(s):
while char in char_set:
char_set.remove(s[left])
left += 1
char_set.add(char)
max_len = max(max_len, right - left + 1)
return max_len6. Invert a Binary Tree
A classic recursive tree manipulation problem.
def invert_tree(root):
if not root:
return None
root.left, root.right = invert_tree(root.right), invert_tree(root.left)
return root7. Implement a Queue using Stacks
Tests knowledge of data structure properties and how to simulate one with another.
class MyQueue:
def __init__(self):
self.s1 = []
self.s2 = []
def push(self, x):
self.s1.append(x)
def pop(self):
if not self.s2:
while self.s1:
self.s2.append(self.s1.pop())
return self.s2.pop()8. Product of List Except Self
A tricky list problem that can be solved efficiently without division.
def product_except_self(nums):
n = len(nums)
result = [1] * n
prefix = 1
for i in range(n):
result[i] = prefix
prefix *= nums[i]
postfix = 1
for i in range(n - 1, -1, -1):
result[i] *= postfix
postfix *= nums[i]
return result9. Rotate a Matrix
An in-place matrix manipulation problem requiring careful indexing.
def rotate(matrix):
n = len(matrix)
for i in range(n): # Transpose
for j in range(i, n):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
for i in range(n): # Reverse each row
matrix[i].reverse()10. First Non-Repeating Character
Requires use of a hash map or dictionary to count character frequencies.
import collections
def first_uniq_char(s):
count = collections.Counter(s)
for i, char in enumerate(s):
if count[char] == 1:
return i
return -1Senior Developer Challenges
1. Merge K Sorted Lists
Tests efficient merging using a min-heap from the `heapq` module.
import heapq
def merge_k_lists(lists):
heap = [(l.val, i) for i, l in enumerate(lists) if l]
heapq.heapify(heap)
head = tail = ListNode(None)
while heap:
val, i = heapq.heappop(heap)
tail.next = ListNode(val)
tail = tail.next
node = lists[i] = lists[i].next
if node:
heapq.heappush(heap, (node.val, i))
return head.next2. Trapping Rain Water
A classic problem requiring an optimal two-pointer approach.
def trap(height):
if not height: return 0
l, r = 0, len(height) - 1
left_max, right_max = height[l], height[r]
water = 0
while l < r:
if left_max < right_max:
l += 1
left_max = max(left_max, height[l])
water += left_max - height[l]
else:
r -= 1
right_max = max(right_max, height[r])
water += right_max - height[r]
return water3. Word Break
A dynamic programming problem testing string segmentation.
def word_break(s, word_dict):
word_set = set(word_dict)
dp = [False] * (len(s) + 1)
dp[0] = True
for i in range(1, len(s) + 1):
for j in range(i):
if dp[j] and s[j:i] in word_set:
dp[i] = True
break
return dp[len(s)]4. LRU Cache
A system design problem elegantly solved with `collections.OrderedDict`.
from collections import OrderedDict
class LRUCache(OrderedDict):
def __init__(self, capacity: int):
self.capacity = capacity
def get(self, key: int) -> int:
if key not in self:
return -1
self.move_to_end(key)
return self[key]
def put(self, key: int, value: int) -> None:
if key in self:
self.move_to_end(key)
self[key] = value
if len(self) > self.capacity:
self.popitem(last=False)5. Find Median from Data Stream
Requires balancing two heaps to maintain the median in real-time.
import heapq
class MedianFinder:
def __init__(self):
self.small = [] # max-heap
self.large = [] # min-heap
def addNum(self, num):
heapq.heappush(self.small, -1 * num)
if self.small and self.large and (-1 * self.small[0]) > self.large[0]:
val = -1 * heapq.heappop(self.small)
heapq.heappush(self.large, val)
if len(self.small) > len(self.large) + 1:
val = -1 * heapq.heappop(self.small)
heapq.heappush(self.large, val)
if len(self.large) > len(self.small) + 1:
val = heapq.heappop(self.large)
heapq.heappush(self.small, -1 * val)
def findMedian(self):
if len(self.small) > len(self.large):
return -1 * self.small[0]
if len(self.large) > len(self.small):
return self.large[0]
return (-1 * self.small[0] + self.large[0]) / 2.06. Number of Islands
A graph traversal problem on a grid, typically solved with DFS or BFS.
def num_islands(grid):
if not grid: return 0
rows, cols = len(grid), len(grid[0])
visited = set()
islands = 0
def dfs(r, c):
if (r not in range(rows) or
c not in range(cols) or
grid[r][c] == '0' or (r, c) in visited):
return
visited.add((r, c))
dfs(r + 1, c); dfs(r - 1, c); dfs(r, c + 1); dfs(r, c - 1)
for r in range(rows):
for c in range(cols):
if grid[r][c] == '1' and (r, c) not in visited:
dfs(r, c)
islands += 1
return islands7. Longest Palindromic Substring
A dynamic programming problem or can be solved with an “expand from center” approach.
def longest_palindrome(s):
res = ""
res_len = 0
for i in range(len(s)):
# Odd length
l, r = i, i
while l >= 0 and r < len(s) and s[l] == s[r]:
if (r - l + 1) > res_len:
res = s[l:r+1]
res_len = r - l + 1
l -= 1; r += 1
# Even length
l, r = i, i + 1
while l >= 0 and r < len(s) and s[l] == s[r]:
if (r - l + 1) > res_len:
res = s[l:r+1]
res_len = r - l + 1
l -= 1; r += 1
return res8. Coin Change
A classic dynamic programming problem to find the minimum number of coins for a given amount.
def coin_change(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for coin in coins:
for i in range(coin, amount + 1):
dp[i] = min(dp[i], dp[i - coin] + 1)
return dp[amount] if dp[amount] != float('inf') else -19. Implement Trie (Prefix Tree)
Tests knowledge of specialized tree data structures for efficient string searching.
class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word):
node = self.root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end_of_word = True10. Regular Expression Matching
A highly complex dynamic programming problem involving pattern matching logic.
def is_match(s, p):
dp = [[False] * (len(p) + 1) for _ in range(len(s) + 1)]
dp[0][0] = True
for j in range(1, len(p) + 1):
if p[j-1] == '*':
dp[0][j] = dp[0][j-2]
for i in range(1, len(s) + 1):
for j in range(1, len(p) + 1):
if p[j-1] == '.' or p[j-1] == s[i-1]:
dp[i][j] = dp[i-1][j-1]
elif p[j-1] == '*':
dp[i][j] = dp[i][j-2]
if p[j-2] == s[i-1] or p[j-2] == '.':
dp[i][j] |= dp[i-1][j]
return dp[len(s)][len(p)]Tips to Prepare for Python Coding Challenges
- Master the Fundamentals: Have a strong grip on Python’s core data types (lists, tuples, dictionaries, sets) and control flow.
- Embrace Pythonic Code: Practice using list comprehensions, generators, and built-in functions (`map`, `filter`) to write clean, efficient, and readable solutions.
- Know Your Standard Library: Get familiar with essential modules like `collections` (especially `defaultdict`, `Counter`, `deque`), `itertools`, and `heapq`. They can drastically simplify complex problems.
- Understand Time and Space Complexity: Be ready to discuss the complexity (Big O notation) of your solutions. This is crucial in mid-level and senior interviews.
- Practice on a Whiteboard: Simulate real interview conditions by solving problems without an IDE. This helps you focus on the logic rather than relying on autocompletion.
- Communicate Your Thought Process: During an interview, talk through your solution. Explain your approach, why you chose a particular data structure, and what trade-offs you’re making.
Conclusion
Every great developer was once a beginner. While these challenges might seem tough, consistent practice is the best way to build confidence and develop the problem-solving instincts needed to excel in any technical interview. Keep coding!


