cswork / libraryOpen practice workspace

Articles

Pseudocode in a Coding Interview: When to Sketch and When to Write Runnable Code

Learn when to sketch pseudocode and when runnable interview code is required. Practice a contract-to-code example, edge cases, and submission checks.

Pseudocode in a coding interview is useful when it makes an algorithm easier to agree on and implement. It becomes a problem when it replaces the deliverable the interviewer or assessment actually requires. A clear sketch can explain your plan; it cannot demonstrate that your chosen language, function signature, state updates, and tests work together.

Official guidance: Microsoft's technical-interview page asks candidates to clarify ambiguities and plan before implementation, while explicitly requiring real code rather than pseudocode in its coding section. These expectations are compatible: discuss the approach, then implement it. Our recommendation: treat the sketch as a bridge with a clear exit condition, such as an agreed invariant and data structure.

Start with a concrete translation drill, such as Return the Ten Most Frequent Words: explain the tie-breaking rule, then implement and test that exact rule.

Can you use pseudocode in a coding interview?

The useful answer depends on what you are being asked to produce. A brief algorithm discussion and a final submitted program serve different purposes. Look at the invitation, task instructions, and environment before deciding how much abstraction is appropriate.

Official guidance: Amazon's SDE II preparation page also specifies syntactically correct code instead of pseudocode for its coding discussion. That is evidence about the published SDE II guidance, not a rule for every employer, role, or interview stage.

Official platform fact: HackerRank documents coding questions as code submissions evaluated with predefined test cases. Its coding-question documentation also describes configurable languages and function signatures. A prose algorithm cannot fulfill an executable coding task's contract simply because its idea is correct.

Evidence boundary: This article does not use candidate reports to estimate how often interviewers accept pseudocode. The following matrix and worked example are original preparation tools. They help interpret instructions; they do not override them.

Format or instructionUseful role for a sketchDeliverable to verify
Online assessment with executable test casesPrivate planning or permitted scratch work before implementationCode in an allowed language that fits the supplied interface and submission workflow
Live coding round requiring runnable codeExplain the algorithm and invariant briefly before typingSyntactically valid implementation, with tests or a reasoned trace in the available tool
Algorithm discussion explicitly asking for pseudocodeDescribe control flow, data structures, and costs preciselyThe requested pseudocode, including meaningful edge cases and a correctness argument
System-design discussionIllustrate one operation when it clarifies a design choiceThe requested architecture and contracts; executable code only if the task asks for it
Paper or whiteboard exerciseFollow the stated notation and level of detailThe specified answer format; the absence of a compiler alone does not establish permission

A narrow clarification helps when the instruction is ambiguous: “Would you like runnable Python for this part, or an algorithm sketch first?” If real code is already required, move toward it instead of repeatedly renegotiating the format.

A good sketch exposes implementation decisions

Weak pseudocode hides the work inside phrases such as “find a matching value” or “handle edge cases.” Those phrases leave the interviewer unable to inspect which state exists, when it changes, or why the result is correct.

A useful sketch names the operations that matter. For a hash-map approach, explain what the keys and values represent, whether membership is checked before insertion, and what happens when a search fails. You can leave out language-specific punctuation while retaining algorithm-specific precision.

Consider these two plans:

Weak: Find two numbers that match the target and return them.

Precise: Scan left to right. For each value, look for its
complement in a map of earlier values to indices. If found,
return those two indices. Otherwise store the current value
and index. Return no result after the scan ends.

The second plan is still a sketch, but it has a state model and operation order. It is ready to translate because the next question is about language mechanics rather than an undisclosed algorithm.

Keep the transition visible: “The map contains only earlier positions, so a lookup cannot reuse the current item. I will implement that order now.” This is an original example of an explanation, not a quoted employer script.

Worked exercise: contract, invariant, pseudocode, Python

Given a list of integers and an integer target, return any pair of distinct, zero-based indices whose values add to the target. Return None if no pair exists. Duplicate values and negative values are allowed. Do not mutate the input.

“Any pair” matters. This contract does not require the lexicographically smallest pair, all pairs, or a particular order of discovery. A solution to one of those variants needs additional reasoning. Likewise, returning values instead of indices would solve a different task.

Start with an invariant: immediately before processing position i, every index stored in seen is smaller than i, and each stored index points to the value used as its key. A key may retain just one earlier occurrence because any valid pair is acceptable.

The pseudocode follows directly:

seen = empty map from integer value to earlier index
for each index i and value in nums:
    complement = target - value
    if complement is a key in seen:
        return (seen[complement], i)
    seen[value] = i
return None

Now translate it into runnable Python:

def find_pair(nums, target):
    seen = {}
    for i, value in enumerate(nums):
        complement = target - value
        if complement in seen:
            return (seen[complement], i)
        seen[value] = i
    return None

Each line has a job. enumerate supplies positions as well as values. Membership tests map keys. The lookup precedes the assignment, and the final return handles exhaustion. The function leaves nums unchanged.

For correctness, a returned pair has the required sum by the complement calculation. Its indices are distinct because the stored index precedes the current one. If a valid pair exists at positions j < i, the first value has been stored when the scan reaches i; even if another occurrence replaced its index, that earlier occurrence has the same value and still forms a valid pair.

With average constant-time map operations and unit-cost integer arithmetic, the expected time is O(n) and the auxiliary space is O(n). Those assumptions belong in the explanation. The sketch's word “lookup” does not make every possible implementation constant time.

Trace the mutation order before optimizing

Use [3, 3] with target 6 to connect the invariant to actual state:

PositionCurrent valueMap before lookupDecision
03EmptyComplement absent; store 3: 0
133: 0Complement present; return (0, 1)

Two equal values are valid because they occupy different positions. Compare the single-element input [3]: the same target must produce None.

Now deliberately move seen[value] = i above the membership check. With [3], the map contains the current item before lookup and the function can return (0, 0). That counterexample pinpoints the defect. “Use a hash map” was insufficient; the mutation order carries the distinct-index guarantee.

This is a useful stopping point for pseudocode. The contract, invariant, and counterexample are established. Continuing to polish the sketch while avoiding implementation adds little evidence about whether you can finish the task.

Test properties as well as examples

Test cases should target a claim. Empty input checks exhaustion. A single matching value checks that an item cannot pair with itself. Duplicates check distinct positions; negatives check the complement arithmetic.

Input and targetExpected propertyDefect it can reveal
[], 0NoneMissing no-result path
[3], 6NoneInsert-before-lookup self-pairing
[3, 3], 6Two distinct indicesIncorrect duplicate handling
[-2, 7], 5A valid pairIncorrect assumptions about positive values
[0, 0], 0A valid pairConfusing a zero value or index with absence
[1, 2], 9NoneReturning an invalid fallback pair

Because the contract allows any pair, a general test should check validity rather than demand one arbitrary pair:

nums = [1, 4, 2, 3]
before = nums.copy()
pair = find_pair(nums, 5)
assert pair is not None
i, j = pair
assert 0 <= i < len(nums) and 0 <= j < len(nums)
assert i != j and nums[i] + nums[j] == 5
assert nums == before

For offline preparation, compare small inputs against a separate brute-force oracle that tries every distinct pair. If the oracle finds none, the implementation must return None; otherwise its output must satisfy the contract. This catches more than reproducing the optimized algorithm inside the test.

These checks establish evidence for this exercise's finite test set. They are not proof that a different assessment's hidden cases will pass. Change the tests when the real task changes its contract.

Handle syntax uncertainty without leaving placeholders

When you know the algorithm but hesitate over a library call, identify the uncertainty precisely. “I need to confirm how this map checks membership” is actionable. “The rest is straightforward” leaves an implementation gap.

Use the language you can implement reliably, subject to the task's allowed choices. During preparation, practice its map, set, queue, sorting, and iteration operations in executable snippets. In the interview, use documentation or other assistance only within the stated rules. A sketch is not permission to consult an unauthorized tool.

Read the supplied function signature before adapting the example. A grader may expect a list, an exception, or a sentinel instead of our tuple-or-None result. A function task may require a return value while a standalone program requires formatted output. Debug prints can also corrupt a required output stream.

Make the smallest correct adaptation. Do not replace a working input harness merely to make the submission resemble your practice notebook. The boundary between your function and the runner is part of the executable contract.

Move from a successful run to a completed submission

Official platform fact: HackerRank's candidate instructions for modifying submissions distinguish running edited code from submitting the changed answer. After a late correction, follow the actual submission control and verify the saved state. Do not infer completion solely from a passing local run.

Our preparation recommendation: reserve room for implementation, checks, and the final delivery action. There is no universal number of minutes for the sketch. Stop planning when you can explain the contract, central invariant, and chosen operations; continue planning if one of those remains unresolved.

Before declaring completion, check that no placeholder helper remains, the output fits the required interface, and the final saved version includes your latest fix. If time ends with incomplete code, explain the exact unfinished behavior and the tests still needed. That is an accurate handoff, not a substitute for the required program.

Practice the translation on different task shapes

QuestionTranslation skill to practice
Return the Ten Most Frequent WordsTurn ranking and lexical tie-breaking into a precise sort key and deterministic tests
Implement a BFS web crawlerSpecify queue, visited-state updates, duplicate handling, and hostname filtering
First-Match CIDR Firewall: Status of an IP Address or a Whole CIDR BlockPreserve rule order and explain why a whole-block answer needs stronger reasoning than one-address matching
Connect JSON Coordinates Through a Documented Drawing APITranslate geometry semantics and documented interface details into actual requests
Debug a Test-Driven C++ ProjectUse executable test failures to locate the gap between intended and implemented behavior

Start with Implement a BFS web crawler. State when a URL enters the visited set, implement that decision, and test repeated links. The goal is to make your explanation predict what your program actually does.

Sources and Further Reading