Explaining Your Approach and Its Cost Out Loud
28 min · Intermediate
Need help? Ask a tutor on WhatsApp (opens in a new tab)A coding interview scores how you think as much as the final code. This lesson gives you a fixed order to speak in, plain words for time and space, and the hidden costs of Python calls that interviewers listen for. To practise it, use the Python DSA 150 sheet at /learn/python/dsa-sheet.
Say your plan before you type
A think-aloud routine is a fixed order of spoken steps in a coding interview: restate, example, brute force, better idea, code, test, cost. It lets the interviewer follow and correct you early.
An interviewer cannot see your thoughts, so say them. A fixed order keeps you calm and shows how you think.
The order is: restate the problem, try one small example, say the slow way, find the repeated work, code the better way, then test it aloud. Revise: Brute force to better solutions (opens in a new tab)
- Restate the input and output in your own words, and ask about empty input, duplicates and negative numbers.
- Say the brute force with its cost first. It proves you can solve it, even if slowly.
- Name the repeated work, then pick the tool that removes it: a set, a dict, sorting, two pointers or a heap.
- Finish with one dry run on a small input, then state time and space.
Say time and space in plain words
Time cost is how the number of steps grows as the input size n grows. Space cost is how much extra memory you use beyond the input. Both are stated in Big O, such as O(n) or O(n log n).
Say what n means, then how the work grows with n. Then say how much extra memory you keep.
def has_duplicate(items): seen = set() # extra memory: up to n items for item in items: # one pass: n steps if item in seen: # set lookup: one step on average return True seen.add(item) return FalseExample 1 · Two sum, said aloud: brute force then dict
def two_sum_brute(nums, target): # Brute force: try every pair. O(n^2) time, O(1) space. for i in range(len(nums)): for j in range(i + 1, len(nums)): if nums[i] + nums[j] == target: return [i, j] return []
def two_sum(nums, target): # Repeated work: searching for the partner. A dict makes it O(1). seen = {} # value -> index; O(n) space for i, value in enumerate(nums): if target - value in seen: return [seen[target - value], i] seen[value] = i return []
print(two_sum_brute([8, 3, 11, 5], 14))print(two_sum([8, 3, 11, 5], 14))print(two_sum([1, 2], 10))[1, 2] [1, 2] []
What this code does
- The comments are the sentences you would say. The brute force tries every pair, the dict version remembers each value and looks for its partner.
- The dict version is one pass: O(n) time and O(n) space. Always test the no-answer case too.
Say it like this: "One pass over n items, and each set lookup is constant on average, so O(n) time. The set can hold n items, so O(n) space."
If asked for less memory, say that sorting first gives O(n log n) time with little extra space.
Know what Python operations really cost
A hidden cost is work done inside a single line of Python, such as a slice that copies a list or an in test that scans every item. Say it aloud so the interviewer knows you counted it.
Interviewers listen for the cost of the library calls you use. A one-line Python call can hide a loop. Revise: The real cost of Python operations (opens in a new tab)
x in some_listscans the list, O(n).x in some_setor a dict is O(1) on average.a[1:]makes a copy, O(k) for k items.list.pop(0)andlist.insert(0, x)shift every item, O(n); usecollections.deque.text += chin a loop can be O(n squared) in the worst case; collect pieces in a list and call''.join(pieces).sorted(items)is O(n log n) time and O(n) space;items.sort()sorts in place but is still O(n log n) time.
Example 2 · The hidden cost of slicing in binary search
def search_slice(items, target): copied = 0 base = 0 while items: mid = len(items) // 2 if items[mid] == target: return base + mid, copied if items[mid] < target: items = items[mid + 1:] base += mid + 1 else: items = items[:mid] copied += len(items) return -1, copied
def search_index(items, target): low, high = 0, len(items) - 1 while low <= high: mid = (low + high) // 2 if items[mid] == target: return mid if items[mid] < target: low = mid + 1 else: high = mid - 1 return -1
data = list(range(0, 2000, 2))print(search_slice(data, 1998))print(search_index(data, 1998))(999, 985) 999
What this code does
- Both find index 999. The slicing version also reports how many items it copied on the way, so its real cost is far above O(log n).
- Moving two indexes costs nothing extra. In an interview, prefer indexes and say why.
Example 3 · Use a deque when you remove from the front
from collections import deque
queue = deque(["t1", "t2", "t3"]) # support tickets waitingqueue.append("t4")print(queue.popleft()) # O(1); list.pop(0) would be O(n)print(queue.popleft())print(list(queue))t1 t2 ['t3', 't4']
What this code does
popleftremoves from the front in O(1). A list would shift every remaining item.- Say "I use a deque because I remove from the front". It is a small sentence that shows you know the cost.
Average, worst case and amortised
Amortised cost is the average cost per operation over a long run of operations, even when a single operation is sometimes expensive. List append is O(1) amortised.
Say which case you mean. A dict lookup is O(1) on average but can degrade in a very unlucky case. Appending to a list is O(1) amortised: most appends are cheap and an occasional resize is costly, but the average per append stays constant.
Example 4 · Recursion depth is space, and Python has a limit
def total_recursive(n): if n == 0: return 0 return n + total_recursive(n - 1)
def total_loop(n): result = 0 for value in range(1, n + 1): result += value return result
try: print(total_recursive(5000))except RecursionError: print("recursion too deep")print(total_loop(5000))recursion too deep 12502500
What this code does
- Each recursive call keeps a frame on the call stack, so this uses O(n) space. CPython stops at about 1000 frames by default.
- The loop uses O(1) space. For deep input, say you would convert the recursion to a loop or an explicit stack.
Next step
Check your understanding
12 quick questions