Python Coding Challenges for Intermediate: 5 With Solutions, and a Bot AI to Practice On
Key takeaways
- An intermediate challenge is one where the problem statement does not tell you which data structure to use.
- Most intermediate interview questions reduce to one move: keep a small auxiliary structure so you avoid re-examining data you have already seen.
- Time-box a brute-force attempt to 25 minutes; if you cannot produce a slow but correct version, the challenge is above your level.
- Re-solve each challenge from a blank file the next day; anything you re-derive yourself sticks, anything you copy-paste does not.
- Bot coding games like thebotslam give intermediate practice a persistent opponent and immediate feedback, but do not drill interview patterns directly.
Table of contents
- What makes a coding challenge 'intermediate' in Python?
- Which Python coding challenge patterns show up most in interviews?
- Five intermediate Python challenges with worked solutions
- How should you attempt a challenge before reading the solution?
- What are the most common wrong approaches to intermediate challenges?
- Which websites offer Python coding challenges with solutions?
- How do you turn a failed challenge attempt into a learning step?
- What Reddit communities are useful for discussing Python challenges?
- How do competitive bot games give intermediate practice a goal?
The best Python coding challenges for intermediate learners are ones that teach a named reasoning pattern, like two-pointer or memoization, with a fully worked solution you can compare against your own attempt. This guide gives you five such challenges, the common wrong approach for each, and a way to practice deliberately instead of grinding random problems.

What makes a coding challenge 'intermediate' in Python?
An intermediate challenge is one where the problem statement does not tell you which data structure to use. A beginner exercise says "reverse this string." An intermediate one says "find the shortest path," leaving you to decide whether a set, a heap, or a plain dict does the work.
Skills an intermediate challenge assumes you already have
You can write loops, functions and classes without looking anything up. You know what a dictionary costs to read from and why a list scan gets slow. If you are still searching "how to append to a list Python," grind those first.
The jump from syntax drills to choosing your own data structures
The real skill is picking a structure before writing code, then defending that choice. Interview prep guides group problems by pattern for exactly this reason: the pattern, not the syntax, is what gets tested. Bot games such as thebotslam force the same decision under a deadline: what your robot's brain remembers, and how, is your choice, and a bad one loses the match.
Which Python coding challenge patterns show up most in interviews?
Interview problems cluster around a handful of recurring patterns. Drill these first and most intermediate questions become recognisable rather than new.
Two-pointer and sliding window
Two pointers let you scan an array from both ends or maintain a running window over a contiguous slice. They show up in problems about pairs, subarrays and deduplication, and they turn O(n²) brute force into O(n). The skill is knowing when to shrink or expand the window.
Hash map lookups and memoization
A dictionary trades memory for speed: count frequencies, cache results, or map values to indices for O(1) lookups. Memoization is the same idea applied to recursion, and it is the standard fix for exponential runtimes.
Graph traversal and BFS
BFS finds shortest paths in unweighted graphs; DFS explores structure. Interviews dress these up as grids, trees or dependency lists, but the core loop barely changes.
When each pattern applies
| Signal in the problem | Pattern to reach for |
|---|---|
| Sorted array, pair sums, palindromes | Two pointers |
| Longest/shortest subarray or substring | Sliding window |
| Repeated lookups, counting, caching | Hash map or memoization |
| Shortest path, levels, nearest exit | BFS |
| All paths, cycles, connected parts | DFS |
The same judgement transfers to bot coding: recognising whether your robot needs a fast lookup, a path to the flag, or a scan of nearby opponents. thebotslam's rules for sharing information with teammates are a worked example of deciding what state to compute, keep and broadcast.
Five intermediate Python challenges with worked solutions
Each solution below is standard Python 3. Try each challenge yourself first (see the next section for how), then compare.
Challenge 1: longest substring without repeating characters (sliding window)
Walk two indices across the string while a set tracks the current window. When a repeat appears, shrink from the left until it's gone. The wrong approach is generating every substring and checking each one, which turns a linear pass into O(n²) or worse. The pattern interviewers test: do you recognize that a window only ever moves forward?
def longest_unique(s):
seen = set()
left = best = 0
for right, ch in enumerate(s):
while ch in seen: # shrink from the left until ch is gone
seen.remove(s[left])
left += 1
seen.add(ch)
best = max(best, right - left + 1)
return best
longest_unique("abcabcbb") # 3 ("abc")
Challenge 2: two-sum with a hash map
Store each number's index in a dict as you scan, checking first whether target - num is already there. One pass, O(n). The wrong approach is sorting first and losing the indices, or nesting two loops. The pattern: trading memory for speed with a lookup table.
def two_sum(nums, target):
index = {} # number -> where we saw it
for i, num in enumerate(nums):
if target - num in index:
return index[target - num], i
index[num] = i
return None
two_sum([2, 7, 11, 15], 9) # (0, 1)
Challenge 3: coin change with memoization
Recursion on the remaining amount, caching results keyed by that amount. The wrong approach is plain recursion without a cache, which recomputes the same subproblem exponentially many times. The pattern: spotting overlapping subproblems and reaching for functools.lru_cache or a manual dict, both documented in Python's standard library reference.
from functools import lru_cache
def coin_change(coins, amount):
@lru_cache(maxsize=None)
def fewest(left): # fewest coins that make `left`
if left == 0:
return 0
best = float("inf")
for c in coins:
if c <= left:
best = min(best, fewest(left - c) + 1)
return best
n = fewest(amount)
return -1 if n == float("inf") else n
coin_change([1, 2, 5], 11) # 3 (5 + 5 + 1)
Challenge 4: rotate a matrix in place (index arithmetic)
Rotate 90 degrees clockwise by transposing (swap m[i][j] with m[j][i]), then reversing each row. The wrong approach is building a new matrix, which fails the "in place" requirement and hides the real lesson: index arithmetic. The pattern: decomposing one rotation into two simpler operations.
def rotate(m):
n = len(m)
for i in range(n): # transpose: swap across the diagonal
for j in range(i + 1, n):
m[i][j], m[j][i] = m[j][i], m[i][j]
for row in m: # then reverse each row
row.reverse()
m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
rotate(m) # m is now [[7, 4, 1], [8, 5, 2], [9, 6, 3]]
Challenge 5: valid parentheses with a stack
Push openers, pop and compare on each closer, and check the stack is empty at the end. The wrong approach is counting brackets, which passes "([)]" when it shouldn't. The pattern: last-in-first-out matching.
def valid(s):
pairs = {")": "(", "]": "[", "}": "{"}
stack = []
for ch in s:
if ch in "([{":
stack.append(ch)
elif ch in pairs:
if not stack or stack.pop() != pairs[ch]:
return False
return not stack
valid("([)]") # False
Why these five matter more than a hundred random problems
Every one of these is the same move in disguise: keep a small auxiliary structure (a set, a dict, a cache, an index pair, a stack) that lets you avoid re-examining data you've already seen. That is the single reasoning pattern behind most intermediate interview questions, and it is why grinding five hundred shuffled problems teaches less than mastering five and then writing them again from scratch a week later. When you can rebuild the sliding window without looking it up, you haven't memorized an answer, you've acquired a tool.
The same move in a bot's AI
The move shows up in a robot programming game too. A thebotslam bot's scanner sees one 30° slice of the field each tick. To know which way is quietest, a bot could sweep the whole circle every time, or it can remember what each slice held and look the answer up. Bot Python is a subset of Python that runs on a tiny robot CPU: there are no dicts or sets, so the auxiliary structure is a fixed-size list.
from bot import Chassis, Scanner, wait
chassis = Chassis(0)
scanner = Scanner(1)
slices = [0] * 12 # contacts last seen in each 30° slice around the bot
look = 0 # the slice the scanner points at: 0 to 11
while True:
wait()
# Count what this slice holds, and remember it.
seen = 0
for i in range(4):
if scanner.ping(i):
seen += 1
slices[look] = seen
# The quietest slice: one pass over twelve remembered numbers,
# instead of sweeping the whole circle again to find out.
best = 0
for s in range(12):
if slices[s] < slices[best]:
best = s
# Turn toward it and drive.
off = best * 30 + 15 - chassis.heading
while off >= 180:
off -= 360
while off < -180:
off += 360
chassis.turn = off / 45
chassis.forward = 1
# Point the scanner at the next slice for next tick.
look = (look + 1) % 12
scanner.sense = look * 30 + 15
It runs on any chassis with a scanner as its first mounted part (channel 1). Working inside those limits (fixed-point numbers, fixed-size lists, 512 CPU cycles a tick) is its own kind of challenge: you choose your structures because you have to.
How should you attempt a challenge before reading the solution?
Time-box, then write brute force first
Give yourself 25 minutes and write the ugliest working version you can. A slow, correct brute force beats an elegant half-solution because it gives you something to measure against. If you cannot produce brute force in 25 minutes, the challenge is above your current level; drop down one.
Name the pattern before you code
Before optimizing, say the pattern out loud: "this is a sliding window" or "this is a BFS on a grid." Naming it forces you to recognize the shape, which is what interviews actually test. If you cannot name it after reading the solution, you have not learned the pattern, only that answer.
Re-solve from scratch the next day
Close everything and rewrite the solution cold the next day. Anything you re-derive yourself sticks; anything you copy-paste does not. This re-solve loop is the same discipline bot coders use when testing a change in a test match: one change, one match, observe, repeat.
What are the most common wrong approaches to intermediate challenges?
Reaching for nested loops when a hash map exists
Two-sum-style problems tempt you into a nested loop that checks every pair. The fix is a dict: walk the list once, store what you have seen, and look up the complement in O(1). If your solution has a loop inside a loop over the same list, ask what a dictionary could remember for you.
Mutating a list while iterating over it
Removing items from the list you are looping over skips elements, because indices shift underneath you. Build a new list with a comprehension, or iterate over a copy. This bug is silent: your code runs and quietly produces the wrong answer.
Optimizing before the brute force works
Write the slow version first, verify it on small inputs, then improve it. That is how to approach a test match too: get a bot on the field before you tune its brain, as the first-match walkthrough shows.
Which websites offer Python coding challenges with solutions?
Comparison of practice sites and programming games
CodinGame turns challenges into small games you solve in Python, with each puzzle showing other players' solutions once you have solved it, so you can read how someone else reasoned through the same problem. Screeps is a persistent MMO where your JavaScript code runs around the clock, better for practicing long-running systems than discrete problems. Robocode has you code tank battle bots in Java, a classic way to practice state and strategy against real opponents.
Where thebotslam fits, and where it falls short
thebotslam gives you the same loop (write a bot's brain, run a test match, watch it lose, fix it) in Python or any of eight other languages, against house bots or other players on the ladder. Where it falls short: it will not drill interview patterns like the worked challenges above, and its Python is a subset without dicts, sets or classes, so it won't drill those either. Use it for the habit of designing state under constraints, not for interview syntax.
How do you turn a failed challenge attempt into a learning step?
Diagnose the bottleneck, not just the bug
A timed-out attempt usually means your algorithm is the problem, not your syntax. Sort your failure into one of three buckets: wrong answer, too slow, or crashed. If it's too slow, find the loop doing the most work and estimate how many times it runs for the largest input. That single estimate tells you whether you need a dictionary instead of a nested loop, or a different approach entirely.
Keep a pattern notebook
After each failed attempt, write one line: the pattern you missed (sliding window, memoization, set lookup) and the moment you'd reach for it next time. Re-attempt the same challenge a week later from a blank file. If you can rebuild the fix without peeking, the failure paid for itself.
What Reddit communities are useful for discussing Python challenges?
r/learnpython is the most active subreddit for exactly this stage: you post your attempt at a challenge, and commenters point out where the logic went wrong rather than just handing over a solution. r/dailyprogrammer historically hosted challenge threads with community solutions to compare against, though posting has largely stopped, so treat it as an archive of problems. When you are stuck on a bot-coding challenge instead of a standalone problem, the fastest feedback loop is running a test match and reading your bot's log, then asking about the specific behavior you saw.
How do competitive bot games give intermediate practice a goal?
Static problem lists stall out because each problem is self-contained: solve it, check the answer, move on, forget it. A bot game like thebotslam, Robocode or Screeps gives you a persistent opponent instead. Your robot's brain is a program with state, decisions and tradeoffs, and a test match tells you immediately whether your code is actually better than the last version.
That feedback loop is what intermediate practice needs. You write a loop for capture the flag, lose, figure out why, and rewrite it. The ladder gives the grind a scoreboard.
FAQ
Are Python coding challenges enough to pass a technical interview, or do I need CS theory too?
For most intermediate roles, pattern recognition beats formal theory. Interviewers test whether you can identify a sliding window, a BFS or a memoization case and implement it correctly, not whether you can prove complexity theorems. Knowing big-O well enough to estimate a loop's cost covers the theory you actually need; deep CS theory matters only for specialized roles.
How long should an intermediate Python challenge take me to solve?
Time-box yourself to 25 minutes for a first brute-force attempt. If you cannot produce a slow but correct version in that window, the challenge is above your current level, so drop down one. Optimizing afterward can take another 15 to 30 minutes. If you still cannot name the pattern after reading the solution, re-solve it cold the next day.
Where can I find Python coding challenges with solutions explained step by step, not just the final code?
Look for resources that show the common wrong approach alongside the correct one, since the failed path is where the learning lives. CodinGame shows other players' solutions once you have solved a puzzle, so you can compare reasoning. r/learnpython commenters typically explain where your logic went wrong rather than handing over a finished answer.
Can I practice these challenges in a competitive game instead of on a problem list?
Partly. In a bot game like thebotslam, Screeps or Robocode, your code faces a persistent opponent and a test match tells you immediately whether the change helped, which fixes the staleness of static lists. The tradeoff: bot games will not drill interview patterns directly, so use them alongside the five worked challenges rather than instead of them.
What Python version and libraries should I use for interview-style challenges?
Use a current Python 3 release and stick to the standard library: dicts, sets, lists, stacks via lists, and functools.lru_cache for memoization. Interviewers expect you to solve problems with built-in structures, not heavy frameworks. Bot coding is stricter still: a thebotslam bot's Python has no imports at all apart from the game's own bot module, which gives it its parts, so everything it knows, it keeps in numbers and fixed-size lists.