Coding-round time management and common problem patterns
40 min · Intermediate
Need help? Ask a tutor on WhatsApp (opens in a new tab)A coding round has three problems and 90 minutes. Most failed rounds are not about missing knowledge: the candidate spends 60 minutes on one problem, never submits a brute force and never tests an edge case.
Splitting 60 to 90 minutes across problems
A time plan for a coding round decides, before you write code, how long each problem gets. You spend the first minutes reading every problem and then rank them by how quickly you can solve them.
The example below turns a 90-minute round with three problems into a schedule: read first, easiest problem first, hardest last.
Example 1 · A 90-minute plan, easiest first
def clock(minutes): return f"{minutes // 60:02d}:{minutes % 60:02d}"
problems = [("C (hard)", 40), ("A (easy)", 15), ("B (medium)", 25)]problems.sort(key=lambda p: p[1])
t = 0print(f"{clock(t)}-{clock(t + 8)} Read all three problems")t += 8for name, minutes in problems: print(f"{clock(t)}-{clock(t + minutes)} Problem {name}") t += minutesprint(f"{clock(t)}-{clock(90)} Buffer: check final submissions")00:00-00:08 Read all three problems 00:08-00:23 Problem A (easy) 00:23-00:48 Problem B (medium) 00:48-01:28 Problem C (hard) 01:28-01:30 Buffer: check final submissions
What this code does
- The problems appear as C, A, B on the screen, but sorting by estimated time gives the order A, B, C. The easy one is submitted within 23 minutes.
- Estimates are guesses. If B is still not working at 00:48, submit its brute force and move to C anyway.
Solve the easiest first and submit it. That locks in marks and calms you down. Give the hardest problem whatever time is left.
- Read all problems first: 5 to 10 minutes.
- If stuck for 10 to 15 minutes, submit a brute force and move on.
- Last 2 to 3 minutes: check every problem has its best version submitted.
Common patterns in fresher coding rounds
A prefix sum array stores running totals, so the sum of any range of elements is one subtraction: prefix[r] - prefix[l - 1]. After one O(n) build, every range query takes O(1).
Most fresher rounds lean on a few patterns. The example below shows one of them, prefix sums, answering range totals in O(1).
Example 2 · Prefix sums: range totals in O(1)
from itertools import accumulate
spend = [120, 80, 300, 50, 200, 150, 90] # UPI spend per day, days 1 to 7prefix = [0, *accumulate(spend)] # prefix[i] = total of the first i days
for l, r in [(2, 5), (1, 7), (4, 4)]: print(f"Days {l} to {r}: {prefix[r] - prefix[l - 1]}")Days 2 to 5: 630 Days 1 to 7: 990 Days 4 to 4: 50
What this code does
prefix[i]holds the total of the first i days, so the total of days l to r isprefix[r] - prefix[l - 1]: one subtraction per query.- With 10⁵ days and 10⁵ queries, adding up each range again would take about 10¹⁰ steps; prefix sums need about 2 × 10⁵.
A pattern is a known way to solve a whole family of problems. Learn to spot it from the wording:
- "How many times", "duplicate", "first unique" → hashing (count or look up in a
dict,Counterorset). - "Sum of elements from day l to day r", many queries → prefix sums.
- "Pair with sum", sorted input → two pointers or hashing.
- "Minimum number of coins or rooms" → sort, then greedy (always take the best option now).
Revise: Prefix sums and range queries (opens in a new tab) and Hashing for lookup (opens in a new tab)
Brute force first, then optimise
A brute force solution tries every possibility directly, such as checking every pair. It is often too slow for the largest tests, but it is quick to write and usually right.
The example below finds the first repeated value twice: with two nested loops (brute force), then with a set.
Example 3 · First repeated value: brute force and set
def brute_force(a): # O(n^2) comparisons = 0 for j in range(1, len(a)): for i in range(j): comparisons += 1 if a[i] == a[j]: return a[j], comparisons return -1, comparisons
def with_set(a): # O(n) seen = set() for v in a: if v in seen: return v seen.add(v) return -1
a = [4, 9, 2, 7, 9, 4, 1]value, comparisons = brute_force(a)print(f"Brute force: {value} after {comparisons} comparisons")print(f"Set: {with_set(a)}")Brute force: 9 after 8 comparisons Set: 9
What this code does
- Both return 9: it is the first value, scanning left to right, that was already seen. The brute force checks every earlier element for each position, which is fine for small n and quick to write.
v in seenis a fast set lookup, so the set version finds the repeat in one pass. Submit the brute force first if the fast idea is not clear yet.
With partial scoring a brute force can earn marks on the small hidden tests, so write it, submit it, then look for the faster idea. A brute force also helps later: it is the reference you compare the fast version against.
Revise: From brute force to better solutions (opens in a new tab)
Testing before you submit
An edge case is an input at the limits of the constraints: an empty string, a single element, all values equal, the largest n, the largest values. Most wrong answers on hidden tests come from these.
The example below runs the edge cases through a fast solution and stress-tests it against a brute force on many small random inputs.
Example 4 · Edge cases and a stress test
import random
def brute_force(a): for j in range(1, len(a)): for i in range(j): if a[i] == a[j]: return a[j] return -1
def with_set(a): seen = set() for v in a: if v in seen: return v seen.add(v) return -1
for e in [[], [5], [3, 3], [1, 2, 3], [10**9, 10**9]]: print(f"{e} -> {with_set(e)}")
rng = random.Random(7)agree = 0for _ in range(200): a = [rng.randrange(10) for _ in range(rng.randint(1, 8))] if brute_force(a) == with_set(a): agree += 1print(f"Random tests: {agree} of 200 agree")[] -> -1 [5] -> -1 [3, 3] -> 3 [1, 2, 3] -> -1 [1000000000, 1000000000] -> 1000000000 Random tests: 200 of 200 agree
What this code does
- The edge cases cover an empty list, one element, a repeat right at the start, no repeat at all and the largest allowed value. Each prints what the problem expects (-1 means no repeat).
- The stress test builds 200 small random lists with a fixed seed and checks that both solutions agree. If one ever differed, printing that list would show the bug at once.
A stress test compares your fast solution with the brute force on many small random inputs. If they ever disagree, you have found a bug and the input that shows it. Use a fixed seed such as random.Random(7) so the same inputs come back each run.
Revise: Choosing edge cases (opens in a new tab) and Stress testing against brute force (opens in a new tab)
Worked example: most frequent roll number
A frequency count stores how many times each value appears, usually in a dictionary or a Counter, in one pass over the data. Looking up and updating a count takes O(1) on average.
Problem: the library logs the roll number of every visit. Print the roll number with the most visits and its count; ties go to the smallest roll number. Constraints: n ≤ 10⁵.
Example 5 · Most frequent roll number: O(n²) and O(n)
from collections import Counter
def brute_force(rolls): # O(n^2): count() rescans the list best, best_count = -1, 0 for r in rolls: count = rolls.count(r) if count > best_count or (count == best_count and r < best): best, best_count = r, count return best, best_count
def with_counter(rolls): # O(n) freq = Counter(rolls) best, best_count = -1, 0 for r, count in freq.items(): if count > best_count or (count == best_count and r < best): best, best_count = r, count return best, best_count
rolls = [104, 101, 104, 230, 101, 104, 230, 101]slow = brute_force(rolls)fast = with_counter(rolls)print(f"Brute force: roll {slow[0]} ({slow[1]} visits)")print(f"Counter: roll {fast[0]} ({fast[1]} visits)")Brute force: roll 101 (3 visits) Counter: roll 101 (3 visits)
What this code does
- Rolls 101 and 104 both have 3 visits, so the tie rule picks the smaller one, 101. The condition
count == best_count and r < besthandles the tie in both versions, so the answer does not depend on the order of the keys. Counter(rolls)counts every roll in one pass. The Counter version then makes one pass over the distinct rolls: O(n) overall.
The brute force counts each value by scanning the whole array again: O(n²), about 10¹⁰ steps for n = 10⁵, far too slow. The frequency count does one pass to count, then one pass over the map to find the winner using the tie rule: O(n).
Next step
Check your understanding
12 quick questions