Turn an unfamiliar task into working code by restating it, collecting examples, planning in pseudocode, implementing, testing and reflecting.
About 35 minBeginner3 exercisesFree
You will be able to
Restate a problem in your own words and name its inputs, outputs and rules
Write concrete examples, including edge cases, before writing code
Break a task into steps and express the plan as pseudocode
Test a function against your examples and use failures to improve it
An algorithm is a precise, step-by-step method for solving a problem. You already write algorithms every time you write a function: "loop over the prices, add each one to a running total, return the total" is an algorithm.
The hard part of a new task is rarely the Python syntax. It is deciding what the steps should be. Imagine your manager at Sahra Logistics asks: "Which hour of the day had the most deliveries yesterday?" If you start typing straight away you will probably write something that works for the first example you think of and breaks on the second. This lesson gives you a process that experienced programmers follow, often without noticing:
Understand — restate the problem. What goes in? What comes out? What are the rules?
Examples — work out a few inputs and their correct outputs by hand, including awkward ones.
Decompose — split the task into smaller steps you already know how to do.
Plan — write the steps as pseudocode: plain-language instructions shaped like code.
Implement — translate the plan into Python.
Test — run your examples. Every mismatch teaches you something.
Reflect — could it be clearer? Faster? What would break it?
Step 1 and 2: understand, then make examples
Restating the delivery question precisely forces decisions. Input: a list of delivery times as "HH:MM" strings. Output: the hour (an integer 0–23) with the most deliveries. Rules you have to choose: what if two hours tie? What if the list is empty?
Examples settle those choices before any code exists:
Input
Output
Why
["09:15", "09:40", "14:05"]
9
two deliveries at 9, one at 14
["14:05", "09:15", "14:30", "09:40"]
9
a tie: we choose the earlier hour
["23:59"]
23
a single delivery
[]
None
nothing to report
The last three rows are edge cases: inputs at the boundary of what the function must handle. Empty input, a single item, ties and duplicates are the usual suspects.
Step 3 and 4: decompose and plan
The task splits into two smaller ones you know from earlier tracks: count deliveries per hour (a dictionary of counts) and find the hour with the largest count (a loop that remembers the best so far). Written as pseudocode:
if there are no times: answer None
counts = empty mapping from hour to count
for each time:
hour = the number before the colon, as an integer
add 1 to counts[hour]
best = None
for each hour from smallest to largest:
if best is None or counts[hour] > counts[best]:
best = hour
answer best
Pseudocode has no strict syntax. Its job is to let you check the logic — "does looping from the smallest hour give the earlier hour on a tie?" — before Python details get in the way. (It does, because > only replaces the best on a strictly larger count.)
Steps 5 and 6: implement the plan, then test it against the examples
defbusiest_hour(times):
ifnot times:
returnNone
counts ={}for t in times:
hour =int(t.split(":")[0])
counts[hour]= counts.get(hour,0)+1
best =Nonefor hour insorted(counts):
if best isNoneor counts[hour]> counts[best]:
best = hour
return best
examples =[(["09:15","09:40","14:05"],9),(["14:05","09:15","14:30","09:40"],9),(["23:59"],23),([],None),]for times, expected in examples:
actual = busiest_hour(times)
status ="ok"if actual == expected else"MISMATCH"print(status, times,"->", actual)
Try it: Add the example (["07:00", "07:30", "08:00", "08:10", "08:20"], 8) to the list and run it. Then change > to >= in the function and see which example breaks.
The table of examples became a tiny test loop. Each row is checked automatically and anything unexpected says MISMATCH. In the Testing track you would write these as assert statements or pytest tests; the idea is the same.
Reflect. The function makes one pass over the times and one pass over at most 24 hours, so it stays fast even for a million deliveries. Could it be clearer? Perhaps collections.Counter would shorten the counting step. Reflection is where you notice such options — after you have something correct.
Predict the output
defbusiest_hour(times):
counts ={}for t in times:
hour =int(t.split(":")[0])
counts[hour]= counts.get(hour,0)+1
best =Nonefor hour in counts:
if best isNoneor counts[hour]> counts[best]:
best = hour
return best
print(busiest_hour(["14:05","09:15","14:30","09:40"]))print(busiest_hour(["09:15","14:05","14:30","09:40"]))
Guided practice · ●●difficulty 2 of 5 · about 8 min
Split a bill into instalments
A furniture shop lets customers pay in equal monthly instalments of whole riyals. When the total does not divide evenly, the first months pay one riyal more.
Write instalments(total, months) that returns a list with one amount per month. Follow this plan:
base = total divided by months, rounded down
extra = the remainder of total divided by months
result = empty list
repeat months times, counting i from 0:
if i is less than extra: add base + 1
otherwise: add base
return result
Examples:
instalments(100, 3) → [34, 33, 33]
instalments(90, 3) → [30, 30, 30]
instalments(2, 4) → [1, 1, 0, 0]
Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.
Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type
Output
Run your code to see its output, or Check to test it against the requirements.
The solution becomes available after you pass, or after all three hints and two checks.
Challenge · ●●●difficulty 3 of 5 · about 12 min
Find the runner-up score
A quiz app shows the top score and the runner-up score. Write runner_up(scores) that returns the second-highest distinct score in a list of integers, or None if there are fewer than two different scores.
Before you code, write your own examples. The rules to respect:
runner_up([70, 85, 90, 60]) → 85
runner_up([90, 90, 85]) → 85 (two people sharing the top score does not make 90 the runner-up)
runner_up([50, 50]) → None
runner_up([]) → None
Do not change the list you are given.
Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.
Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type
Output
Run your code to see its output, or Check to test it against the requirements.
The solution becomes available after you pass, or after all three hints and two checks.
Debugging · ●●difficulty 2 of 5 · about 8 min
Fix the coldest-reading report
A cold-storage warehouse logs freezer temperatures every hour. coldest_hour(readings) should return the index of the first lowest reading, or None for an empty list.
Users report two problems:
For the chiller room, which always stays above zero, readings such as [5, 7, 6] give None instead of 0.
When the lowest temperature appears twice, as in [3, 1, 4, 1], it reports the later one (3) instead of the first (1).
Find and fix the bugs. Test your fix with the examples from the report and with an empty list.
Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.
Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type
Output
Run your code to see its output, or Check to test it against the requirements.
The solution becomes available after you pass, or after all three hints and two checks.
Summary
Restate the problem: name the inputs, the output and every rule, including what happens on ties and empty input.
Write examples by hand before coding; edge cases such as empty, single, duplicates and negatives are part of the specification.
Decompose the task into steps you know and write them as pseudocode to check the logic early.
Turn your examples into automatic checks, then reflect on clarity, speed and inputs that could still break the code.