Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Coding Interview Patterns  Module 2 – Interview toolkits in five languages

Online assessments: input, output and scoring

Read stdin fast and safely, print exactly what the checker expects, reset state between test cases and plan an online assessment around per-test scoring.

  • Intermediate
  • 25 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, Java 27 and Clang 21.0.0
  • By MySmartCoPilot
Free: 25 minutes

What you will learn

  • Parse common stdin formats, such as many test cases, grids and edge lists, quickly and correctly
  • Write output in the exact format a checker compares, all at once
  • Start every test case from fresh structures sized for that case
  • Plan an assessment around per-test scoring and time limits

Before you start

What you’ll learn · Before you start

What you will learn

  • Parse common stdin formats, such as many test cases, grids and edge lists, quickly and correctly
  • Write output in the exact format a checker compares, all at once
  • Start every test case from fresh structures sized for that case
  • Plan an assessment around per-test scoring and time limits

Before you start

On this page

An online assessment runs your program on input files you never see and compares what it prints with the expected output, test by test. Beyond the algorithm, four things decide the score: reading the input fast and without assumptions about its layout, printing exactly the expected text, starting every test case from a clean state, and using the fact that each test scores on its own. This lesson shows a reading template in Python, JavaScript, Java and C++, measures one read against reading line by line, runs two kinds of output checker on near-miss answers, reproduces state that leaks from one test case into the next, and ends with a time plan for a 90-minute, three-problem assessment.

Read everything, then walk through the tokens

Most assessment inputs are a sequence of numbers and words separated by spaces and line breaks: a count T of test cases, then each case with its sizes and data, such as a grid or a list of edges. Reading the whole input at once and splitting it on whitespace handles any layout, including blank lines, extra spaces and a missing final newline, and it is the fastest way in every language. Here is one input of three grids:

cases.txt: three test cases, each a grid Text · cases.txt
3
2 3
#.#
.##
1 1
.
3 2
##
#.
##
Python: one read, then an iterator over the tokens Python · read_cases.py
import sys


def main():
    # Every whitespace-separated token of the input, read in one call, as bytes.
    tokens = iter(sys.stdin.buffer.read().split())
    t = int(next(tokens))
    out = []
    for case in range(1, t + 1):
        rows, cols = int(next(tokens)), int(next(tokens))
        lit = sum(next(tokens).count(b"#") for _ in range(rows))
        out.append(f"Case #{case}: {lit} of {rows * cols}")
    # One write at the end, with a newline after the last line too.
    sys.stdout.write("\n".join(out) + "\n")


main()

Input (standard input)

3
2 3
#.#
.##
1 1
.
3 2
##
#.
##

Output

Case #1: 4 of 6
Case #2: 0 of 1
Case #3: 5 of 6

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 read_cases.py

sys.stdin.buffer.read().split() returns every token as bytes, and iter() with next() walks through them in order, whatever the line breaks. The answer lines go into a list and are written once, with a newline after the last one. The same template in JavaScript reads file descriptor 0, which is standard input, in one call:

JavaScript: read standard input whole, then split JavaScript · read_cases.mjs
import { readFileSync } from "node:fs";

// Standard input is file descriptor 0: read it whole, then split on any whitespace.
const tokens = readFileSync(0, "utf8").split(/\s+/).filter((s) => s.length > 0);
let pos = 0;
const next = () => tokens[pos++];

const t = Number(next());
const out = [];
for (let c = 1; c <= t; c++) {
  const rows = Number(next());
  const cols = Number(next());
  let lit = 0;
  for (let r = 0; r < rows; r++) for (const ch of next()) if (ch === "#") lit++;
  out.push(`Case #${c}: ${lit} of ${rows * cols}`);
}
process.stdout.write(out.join("\n") + "\n");

Input (standard input)

3
2 3
#.#
.##
1 1
.
3 2
##
#.
##

Output

Case #1: 4 of 6
Case #2: 0 of 1
Case #3: 5 of 6

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node read_cases.mjs

In Java and C++ the reading is token by token, but buffered: a BufferedReader with a StringTokenizer that skips blank lines, and cin after sync_with_stdio(false). Both collect the output in one string and print it once.

Java and C++ readers

Java · ReadCases.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class ReadCases {
    static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer tokens = new StringTokenizer("");

    // The next whitespace-separated token, reading more lines as needed (blank lines are skipped).
    static String next() throws IOException {
        while (!tokens.hasMoreTokens()) tokens = new StringTokenizer(in.readLine());
        return tokens.nextToken();
    }

    public static void main(String[] args) throws IOException {
        int t = Integer.parseInt(next());
        StringBuilder out = new StringBuilder();
        for (int c = 1; c <= t; c++) {
            int rows = Integer.parseInt(next());
            int cols = Integer.parseInt(next());
            int lit = 0;
            for (int r = 0; r < rows; r++) {
                for (char ch : next().toCharArray()) if (ch == '#') lit++;
            }
            out.append("Case #").append(c).append(": ").append(lit).append(" of ").append(rows * cols).append('\n');
        }
        System.out.print(out);
    }
}

C++ · read_cases.cpp

#include <algorithm>
#include <iostream>
#include <string>

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int t;
    std::cin >> t;
    std::string out;
    for (int c = 1; c <= t; ++c) {
        int rows, cols;
        std::cin >> rows >> cols;
        long long lit = 0;
        for (int r = 0; r < rows; ++r) {
            std::string row;
            std::cin >> row;  // >> skips spaces and line breaks, blank lines included
            lit += std::ranges::count(row, '#');
        }
        out += "Case #" + std::to_string(c) + ": " + std::to_string(lit) + " of " + std::to_string(rows * cols) + '\n';
    }
    std::cout << out;
}
session.py: runs the commands of a session and prints what they printed Python · session.py
"""Runs shell commands as you would type them in a terminal, and prints the session.

Each line of the script is one command. The session shows it after "$ ", then what it printed (standard output and
standard error together), and, when the command fails, its exit status. The JDK's commands and Homebrew's folders are
added to PATH, so `java` and `g++-16` are the ones named in the lesson.
"""

import os
import subprocess

JDK_BIN = "/opt/homebrew/opt/openjdk/bin"
HOMEBREW_BIN = ["/opt/homebrew/bin", "/usr/local/bin"]


def run(script: str) -> None:
    env = dict(os.environ)
    env["PATH"] = os.pathsep.join([JDK_BIN, env.get("PATH", ""), *HOMEBREW_BIN])
    for command in script.strip().splitlines():
        command = command.strip()
        if not command:
            continue
        print(f"$ {command}")
        result = subprocess.run(command, shell=True, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
        print(result.stdout, end="")
        if result.returncode != 0:
            print(f"[exit status {result.returncode}]")
Both readers on cases.txt Python · readers_session.py
from session import run

# The Java and C++ readers on the same input file.
run("""
java ReadCases.java < cases.txt
clang++ -std=c++23 -O2 -Wall -Wextra read_cases.cpp -o read_cases && ./read_cases < cases.txt
""")

Output

$ java ReadCases.java < cases.txt
Case #1: 4 of 6
Case #2: 0 of 1
Case #3: 5 of 6
$ clang++ -std=c++23 -O2 -Wall -Wextra read_cases.cpp -o read_cases && ./read_cases < cases.txt
Case #1: 4 of 6
Case #2: 0 of 1
Case #3: 5 of 6

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 readers_session.py

In Go, the equivalent is a bufio.Scanner split into words, with strconv for numbers, and a bufio.Writer whose Flush you defer at the start of main, because its buffered output is lost otherwise. The toolkit lessons for Java and C++ time their readers on larger inputs, and the ones for Python and JavaScript cover the rest of each language’s toolkit.

One read against a line at a time

Python’s input() is fine for a few lines and slow for a million: each call reads and decodes one line and strips its newline. On the same file of a million numbers, one per line:

A million numbers, read two ways

Python (make_numbers.py) · make_numbers.py

import random

# One million integers, one per line, after their count: a large test input for the two Python readers.
random.seed(1)
n = 1_000_000
with open("numbers.txt", "w") as f:
    f.write(f"{n}\n")
    f.write("\n".join(str(random.randint(-10**9, 10**9)) for _ in range(n)) + "\n")
print(f"wrote {n} numbers")

Python (read_with_input.py) · read_with_input.py

import time

start = time.perf_counter()
n = int(input())
total = 0
for _ in range(n):
    total += int(input())
print(f"input() per line:      sum {total}, {round((time.perf_counter() - start) * 1000)} ms")

Python (read_with_buffer.py) · read_with_buffer.py

import sys
import time

start = time.perf_counter()
data = sys.stdin.buffer.read().split()
n = int(data[0])
total = sum(map(int, data[1 : n + 1]))
print(f"one read, then split:  sum {total}, {round((time.perf_counter() - start) * 1000)} ms")
Both readers on the same file Python · python_readers_session.py
from session import run

run("""
python3 make_numbers.py
python3 read_with_input.py < numbers.txt
python3 read_with_buffer.py < numbers.txt
""")

Output

$ python3 make_numbers.py
wrote 1000000 numbers
$ python3 read_with_input.py < numbers.txt
input() per line:      sum -230773644225, 3560 ms
$ python3 read_with_buffer.py < numbers.txt
one read, then split:  sum -230773644225, 106 ms

This output changes from run to run: the times depend on the computer and on what else it is running

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 python_readers_session.py

The single read was more than ten times faster. HackerRank’s execution environment page gives Python 3 a time limit of 10 seconds and Java 4, for example, so on a large test the reading method alone can decide whether a correct solution passes. Write output the same way: one sys.stdout.write of a joined list instead of a print per line.

Not affiliated

Based on public information about HackerRank. MySmartCoPilot is not affiliated with HackerRank, and HackerRank’s real environments may differ from what this lesson describes.

Checkers differ. Some compare the output byte for byte; others compare the whitespace-separated tokens and ignore spacing. You rarely know which one an assessment uses, so produce the exact format, and know which mistakes the strict kind punishes:

Four outputs, an exact checker and a lenient one Python · exact_output.py
# What two kinds of checker say about four outputs for the same expected answer.
expected = "Case #1: 4 of 6\nCase #2: 0 of 1\n"
candidates = {
    "exact copy": "Case #1: 4 of 6\nCase #2: 0 of 1\n",
    "space at a line end": "Case #1: 4 of 6 \nCase #2: 0 of 1\n",
    "no final newline": "Case #1: 4 of 6\nCase #2: 0 of 1",
    "no # sign": "Case 1: 4 of 6\nCase 2: 0 of 1\n",
}


def exact(out):
    return out == expected


def by_tokens(out):
    # A lenient checker: compares the whitespace-separated tokens only.
    return out.split() == expected.split()


for name, out in candidates.items():
    print(f"{name:20} exact: {'pass' if exact(out) else 'fail'}   by tokens: {'pass' if by_tokens(out) else 'fail'}")

Output

exact copy           exact: pass   by tokens: pass
space at a line end  exact: fail   by tokens: pass
no final newline     exact: fail   by tokens: pass
no # sign            exact: fail   by tokens: fail

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 exact_output.py

A space at the end of a line and a missing final newline pass a token checker and fail an exact one. A changed label, here Case 1 instead of Case #1, fails both, because it changes a token. Copy labels, separators and capital letters from the problem’s sample output, end every line with a newline, print numbers in the form asked for (no 1e+06, no trailing .0), and compare your output with the sample before you submit.

Text Diff Paste the expected sample output and yours to see a stray space or a missing line.

Reset state for every test case

When one input holds many test cases, everything a solution keeps between them is a bug waiting for test case 2: a global list, a set, a memo dictionary, a counter or a default argument.

A set that survives from one test case into the next Python · state_leak.py
# Distinct rows of each test case's grid. The first version keeps its set between test cases.
cases = [["#.#", ".##", "#.#"], ["#.#", "..."]]

seen = set()


def distinct_rows_leaky(rows):
    for row in rows:
        seen.add(row)
    return len(seen)


def distinct_rows(rows):
    return len(set(rows))


print("leaky:", [distinct_rows_leaky(rows) for rows in cases])
print("fixed:", [distinct_rows(rows) for rows in cases])

Output

leaky: [2, 3]
fixed: [2, 2]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 state_leak.py

The leaky version counts 3 distinct rows in the second grid, because it still holds the rows of the first; the fixed version builds its set inside the function and counts 2. The sample input often has one test case, so this passes the sample and fails the hidden tests. Allocate per test case ([0] * (n + 1) inside the loop), or clear what you reuse; in C++ and Java, clear vectors, maps and arrays, and with T up to 10⁴, size each allocation by that case’s n, not by the maximum n, or allocating alone takes too long.

How assessments score, and a time plan

Many assessments score each hidden test separately. HackerRank’s description of its coding questions is explicit: each test case has a score, a passing test earns all of it, a failing one earns zero, and the total is the sum over the tests that pass. A brute force that is correct but too slow for the largest inputs still passes the small ones, so it earns real points.

That suggests a plan. This one is a suggestion for a 90-minute assessment with three problems, not a rule:

A 90-minute plan: read all problems, solve the easiest fully, bank a brute force on the hardest, optimise, then check formats.0-5 min: read all threeproblems and their limitsSolve the easiest one fully:edge cases, exact outputSubmit a brute forcefor the hardest one:small tests score pointsOptimise where theremaining points areLast 10 min: no new ideas;check formats, resubmitthe best version of each

A plan for a 90-minute, three-problem assessment

Text description of the diagram

The diagram is a sequence of five steps, read from top to bottom.

  1. In the first five minutes, read all three problems and their limits.
  2. Solve the easiest problem fully, with its edge cases and the exact output format.
  3. Submit a brute force for the hardest problem, because its small tests already score points.
  4. Optimise where the remaining points are.
  5. In the last ten minutes, start no new ideas: check output formats and resubmit the best version of each solution.
  1. Read all three problems and their limits first, so you choose the order instead of meeting the hardest one first.
  2. Solve the easiest one fully: edge cases, the exact output format and a test with the largest input you can make.
  3. Submit a brute force for the hardest one before you look for its optimal solution: the small tests score at once.
  4. Spend the middle of the time on the optimisations that unlock the most remaining tests, using the constraints to tell which tests a brute force cannot pass.
  5. In the last ten minutes, start nothing new. Check output formats and make sure the best version of each solution is the one submitted.
Timer Practise with the clock: set 90 minutes and check yourself against the plan.

Practise: many graphs in one input

The exercise reads T graphs given as edge lists and prints two numbers for each. Its starter solution passes a single test case and then falls into two traps of this lesson. The tests include blank lines, 10,000 tiny test cases and one graph of 200,000 nodes.

Exercise · Easy · Python

Read many graphs from one input, the assessment way

An assessment gives you the whole input on standard input and compares your output with the expected text. Here the input holds T test cases. Each starts with a line n m, the number of nodes (numbered 1 to n) and of edges, followed by m lines u v, an undirected edge between two different nodes. The same edge may appear more than once, and each copy counts.

For each test case, print one line Case #k: isolated maxdeg: the number of nodes with no edge, and the largest degree (0 when there are no edges). End every line, the last one included, with a newline.

2
3 2
1 2
2 3
4 0

gives

Case #1: 0 2
Case #2: 4 0

edges.py has a function solve(data) that takes the whole input as a string and returns the whole output as a string. It handles one test case correctly and fails as soon as there are several, or when the input has blank lines or extra spaces, which test files often do. The tests also run 10,000 tiny test cases in one input and one graph of 200,000 nodes, so the solution must be fast too.

Starter code · edges.py

# Degrees of the nodes, sized once for the largest graph the problem allows.
degree = [0] * 200_001


def solve(data):
    """The output for the whole input: one line "Case #k: isolated maxdeg" per test case."""
    lines = data.split("\n")
    t = int(lines[0])
    out = []
    line = 1
    for case in range(1, t + 1):
        n, m = map(int, lines[line].split())
        line += 1
        for _ in range(m):
            u, v = map(int, lines[line].split())
            line += 1
            degree[u] += 1
            degree[v] += 1
        isolated = sum(1 for node in range(1, n + 1) if degree[node] == 0)
        out.append(f"Case #{case}: {isolated} {max(degree[1 : n + 1])}")
    return "\n".join(out) + "\n"
The sample tests · test_edges.py
from edges import solve


def test_one_case():
    """a single path of three nodes"""
    assert solve("1\n3 2\n1 2\n2 3\n") == "Case #1: 0 2\n"


def test_two_cases():
    """the example of the prompt: the second graph has no edges"""
    assert solve("2\n3 2\n1 2\n2 3\n4 0\n") == "Case #1: 0 2\nCase #2: 4 0\n"


def test_repeated_edges_count():
    """three copies of the edge between 1 and 2 give both nodes degree 3"""
    assert solve("1\n2 3\n1 2\n1 2\n2 1\n") == "Case #1: 0 3\n"


def test_isolated_nodes():
    """nodes 3 and 4 have no edge"""
    assert solve("1\n4 1\n1 2\n") == "Case #1: 2 1\n"


def test_blank_lines_and_spaces():
    """blank lines between test cases and two spaces inside a line"""
    assert solve("2\n\n3 1\n1  2\n\n2 0\n") == "Case #1: 1 1\nCase #2: 2 0\n"


def test_no_final_newline_in_the_input():
    """the input may end without a newline; the output still ends with one"""
    assert solve("1\n2 1\n2 1") == "Case #1: 0 1\n"


def test_ten_thousand_tiny_cases():
    """10,000 graphs of two nodes and one edge in one input"""
    t = 10_000
    data = f"{t}\n" + "2 1\n1 2\n" * t
    expected = "".join(f"Case #{k}: 0 1\n" for k in range(1, t + 1))
    assert solve(data) == expected


def test_large_path():
    """a path of 200,000 nodes"""
    n = 200_000
    data = f"1\n{n} {n - 1}\n" + "".join(f"{i} {i + 1}\n" for i in range(1, n))
    assert solve(data) == "Case #1: 0 2\n"
A hint

Two things break when the input holds many test cases. Look at what solve keeps from one test case to the next, and at what it assumes about lines. Reading every token with data.split() and walking through them with an index or iter() makes blank lines and extra spaces harmless.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Interview questions

Fresher · Why read the whole input at once in an online assessment, and how do you do it in Python?

Reading everything in one call is faster and more robust than reading line by line. It is faster because each line read and converted separately costs a call, a decode and a copy, which adds up over a million lines: in this lesson’s run, one read was more than ten times faster than input() per line. It is more robust because splitting on whitespace ignores the layout, so blank lines, extra spaces, numbers split across lines or a missing final newline cannot break the parser. In Python, data = sys.stdin.buffer.read().split() gives every token as bytes; int() accepts them directly, and iter(data) with next() walks through them case by case. Write the output once at the end, joined with newlines and ending with one.

Key takeaways

  • Read the whole input at once, split it on whitespace and walk through the tokens; it is fast and survives any layout.
  • Collect output and write it once; end every line, the last one included, with a newline.
  • Produce the exact sample format: an exact checker fails a trailing space or a missing newline.
  • Start every test case from fresh structures sized for that case.
  • Each test usually scores on its own, so submit a correct brute force early, then optimise.

Check yourself

5 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 5 Which way of reading a large assessment input in Python is both fast and safe against blank lines and extra spaces?

    Choose one answer.

    Show the answer to question 1

    Answer: tokens = sys.stdin.buffer.read().split(), then walk through the tokens

    One read and one split ignore the layout, and they were more than ten times faster than input() per line in the lesson's measurement. Reading line by line breaks as soon as a test file has a blank line or splits a case over lines differently.

  2. Question 2 of 5 The expected output is "Case

    Choose every answer that is right.

    Show the answer to question 2

    Answer:

    • "Case #1: 4" (no final newline)
    • "Case #1: 4 \n" (a space before the newline)
    • "Case 1: 4\n" (no # sign)

    An exact checker fails every difference, whitespace included. A checker that compares tokens would accept the first two and still reject the third, because "Case" "1:" is not "Case" "#1:".

  3. Question 3 of 5 A solution passes the sample, which has one test case, and fails hidden tests with T = 1,000. The algorithm is right. What is the most likely cause?

    Choose one answer.

    Show the answer to question 3

    Answer: A list, set or dictionary that is filled in one test case and not reset before the next

    Anything kept between test cases carries the first case's data into the second, which a one-case sample never shows. Build fresh structures inside the per-case loop, sized for that case.

  4. Question 4 of 5 An assessment scores each hidden test case separately. You have a correct O(n²) solution and 25 minutes left for a problem with n up to 10^5. What should you do first?

    Choose one answer.

    Show the answer to question 4

    Answer: Submit the O(n²) solution now, then look for a faster one

    Each passing test earns its points, and the small tests are within reach of a quadratic solution, so a correct brute force banks points at once. A later, faster submission can only add to them.

  5. Question 5 of 5 T is up to 10^4 and n up to 10^5 per case, with the total of n over all cases at most 2 × 10^5. How should each case allocate its arrays?

    Choose one answer.

    Show the answer to question 5

    Answer: Allocate arrays of size n + 1 for that case

    Sizing by the case's own n keeps the total work proportional to the total input, 2 × 10^5. Allocating the maximum in each of 10^4 cases costs 10^9 element writes, and a never-reset array leaks one case's data into the next.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.