Fast I/O, Judges & Debugging
Read input fast, understand what the judge is really telling you, and find your bug before anyone else does.
▶ guided lesson⚡ 1-minute summary↻ 14 recall cards
before this: Java Arrays & Strings
01 · why it exists
Why this exists, and the weight it carries
since1969–72
Standard input and output
Ken Thompson, Dennis Ritchie and Doug McIlroy at Bell Labs (Unix)
Early Unix gave every program two ready-made files: standard input and standard output (file descriptors 0 and 1). The shell's < and > swapped them for files, so a program never needed to know where its data came from. Pipes appeared in 1972 at Doug McIlroy's suggestion, chaining one program's output into the next one's input. Online judges use exactly this: the test file becomes your stdin, and your stdout becomes a file they compare.
the problem it solvedPrograms could be combined and tested without changing their code — just by redirecting where input comes from and where output goes.
its jobs today
- Online judges feed each test file to your stdin and capture your stdout for comparison.
- Shell pipelines and CI scripts chain tools (
sort,grep,diff) through stdin and stdout.
the weight it carries
Illustrative OA problem: 30 hidden test files, each with up to 10⁵ numbers in and 10⁵ lines out. Your program is started 30 times and every byte passes through stdin and stdout — a slow reader is paid for 30 times.
without it
Every program would need to know file names, and a judge couldn't run any submission the same way.
when · why · how
- when
- Stdin (OA) mode: the template gives you an empty
main. - why
- The judge only sees what you print — nothing else exists for it, so the exact format matters.
- how
- Read
System.inthrough aBufferedReader; write toSystem.outthrough aPrintWriteror oneStringBuilder, and flush.
since1997
Fast input and output in Java
Sun's JDK team (JDK 1.1 readers; Scanner in J2SE 5.0)
JDK 1.1 added character streams, including BufferedReader, which reads through an 8,192-char buffer. StringTokenizer is older still (JDK 1.0); its docs now call it a legacy class, but it remains a fast way to split a line. J2SE 5.0 added Scanner, which parses tokens using regular expressions — very convenient, noticeably slower. And System.out is built with auto-flush on, so each println pushes its line out immediately.
the problem it solvedReading and writing millions of tokens without the I/O itself eating the time limit.
its jobs today
- Online assessments with 10⁵–10⁶ numbers of input or output.
- Batch tools and log processors that stream big files line by line.
the weight it carries
Measured on one desktop (JDK 26, median of 3 runs, fresh JVM each): reading 10⁶ ints took 530 ms with Scanner vs 140 ms with BufferedReader + StringTokenizer; printing 10⁶ lines took 2,478 ms with println per line vs 87 ms with one PrintWriter flush and 48 ms with one StringBuilder print.
without it
A correct O(n) solution can still TLE: on our machine, println alone spent 2.5 s on 10⁶ lines.
when · why · how
- when
- Stdin problems with more than about 10⁵ tokens, or any output with many lines.
- why
- Same O(n) — but buffering and simple parsing cut the constant about 4× for input and 28–52× for output in our measurement.
- how
- The FastReader template (BufferedReader + StringTokenizer) for input;
PrintWriter+flush()or oneStringBuilderfor output.
since1997
Online judges and verdicts
Miguel A. Revilla, University of Valladolid (UVa Online Judge)
The UVa Online Judge in Spain opened to the public in April 1997 with a hundred problems: anyone could submit code and get an automatic verdict. Its 2008 paper splits verdicts into informed ones (AC, WA, Presentation Error) and uninformed ones (TLE, RE, compile error) — a TLE tells you nothing about whether your logic was right. From millions of submissions it also found that after five wrong answers in a row, the next submission was about four times more likely to be wrong than accepted.
the problem it solvedJudging thousands of submissions automatically and fairly, with the same hidden tests and limits for everyone.
its jobs today
- LeetCode, contest sites and OA platforms run every submission against hidden tests with time and memory limits.
- Programming contests (ICPC-style) and university courses grade code the same automatic way.
the weight it carries
Rule of thumb (Laaksonen: "some hundreds of millions of operations" per second): n = 10⁵ with an O(n²) solution is 10¹⁰ steps — about 100 s at 10⁸ per second, far past a 1–2 s limit. O(n log n) is about 1.7 × 10⁶ steps: milliseconds.
without it
Every solution would need a human grader, and "it works on my example" would be the only test.
when · why · how
- when
- Every time you submit: read the verdict as a diagnosis, not a judgement of you.
- why
- WA = logic or format; TLE = complexity or slow I/O; RE = a crash; MLE = memory; CE = didn't compile. Each points to a different fix.
- how
- Match the verdict to its usual causes (the table above), reproduce it with your own test, fix, then resubmit.
since1975
Exceptions and the call stack
John B. Goodenough (the exception-handling paper); Java's designers (JLS Chapter 11)
In December 1975 John Goodenough's paper in Communications of the ACM set out what exception handling in a language should look like. Java built it in from the start: when code breaks a rule, the JVM throws an exception, and control jumps to the nearest enclosing catch that can handle it, abandoning every frame in between. If nothing catches it, the thread ends and the stack trace is printed. Since JDK 15, a NullPointerException message even names what was null (JEP 358).
the problem it solvedErrors that can't be handled where they happen travel to code that can — instead of every function checking and passing error codes by hand.
its jobs today
- Stopping bad input (a token like "7x") from silently producing a wrong answer.
- Pinpointing bugs: the stack trace names the exception, its message and the exact line in your code.
the weight it carries
Illustrative: a 200-line solution crashes on a hidden test. The stack trace narrows 200 lines to one exception type and about 4 frames, one of them naming your file and line. Reading it takes a minute; guessing can take the whole round.
without it
A bad index would read garbage (as in C), or every function would return error codes that someone forgets to check.
when · why · how
- when
- In DSA code you mostly meet exceptions as bugs: let them crash while practising, read the trace, fix the cause.
- why
- Each common exception maps to a typical bug: bounds, null, parse, divide by zero, editing during iteration, deep recursion, giant tables.
- how
- Read the trace top-down, find the first frame in your code, reproduce with a small input. Catch only what you can really handle.
since2002
Assertions (assert)
JSR 41 — spec lead Joshua Bloch
JSR 41, "A Simple Assertion Facility", went final in May 2002 and arrived with J2SE 1.4 as the assert keyword. Oracle's guide spells out the rules: assertions are disabled by default and switched on with -ea; assert expressions must not have side effects; and public methods should check their arguments with real exceptions, not asserts.
the problem it solvedWriting down what you believe is true ("left ≤ right here") so the program tells you the moment it isn't — and costs almost nothing when switched off.
its jobs today
- Checking invariants while practising: "left ≤ right", "count never negative", "the array is sorted here".
- Documenting assumptions in code: an assert is a comment the JVM can check.
the weight it carries
Illustrative: an invariant check inside a loop of 10⁵ steps. With -ea (practice): 10⁵ extra comparisons that stop the program at the exact step the bug appears. Without -ea (a judge, production): the checks are skipped.
without it
A broken state travels silently until it surfaces as a wrong answer, far from its cause.
when · why · how
- when
- Local practice and debugging, for things that should always be true.
- why
- It fails loudly at the first broken assumption, and it's harmless to leave in when disabled.
- how
assert lo <= hi : "lo=" + lo;then runjava -ea Main. Never put needed work inside an assert.
since1947
Debugging and testing your own code
The Harvard Mark II team, including Grace Hopper
In 1947 engineers working on Harvard's Mark II computer found a moth stuck in the machine and taped it into their log book as the "first actual case of bug being found". The Smithsonian, which keeps that log book, notes the word was older — Thomas Edison talked about bugs in electrical circuits in the 1870s. The joke stuck because the work is real: debugging is finding where the program and your belief about it differ.
the problem it solvedA name — and later a discipline — for finding faults systematically instead of by luck.
its jobs today
- Shrinking a failing input until the bug is obvious.
- Writing your own tests — samples, edge cases, stress tests against a brute force — before the judge runs its own.
the weight it carries
Illustrative: a failing input of 10⁵ numbers is unreadable. Dropping one element at a time while it still fails can shrink it to a handful; in this chapter's example 8 numbers shrink to 1, and the bug (best = 0) is obvious at that size.
without it
You'd resubmit and hope. The UVa data shows where that leads: after five wrong answers in a row, the next one was about four times more likely to be wrong than accepted.
when · why · how
- when
- The moment a result surprises you — before you resubmit.
- why
- A small, reproducible failing case turns a mystery into a dry-run of a few steps.
- how
- Samples → edge cases → stress test vs brute force (Mindset chapter) → shrink the failure → dry-run it, or print to
System.err.
02 · plain english
The idea in 30 seconds
On LeetCode a hidden driver calls your method. In many online assessments there is no driver: you read the input from stdin yourself and print the answer to stdout.
Either way a judge runs your code on hidden tests with a time limit and answers in one word: AC, WA, TLE, RE or MLE.
This chapter teaches you to read and print fast, decode those words, and catch your own bug before the judge — or the interviewer — does.
picture this
A judge is like booking an IRCTC Tatkal ticket: the form must be exactly right, and it must arrive before the window closes. A perfect form submitted late still gets nothing — that's a TLE.
03 · remember
What you must know
- Two judging styles: LeetCode calls your method on
class Solution. Stdin (OA) mode runs yourmain, feeds the test onSystem.in, and compares what you print. - Fast input:
BufferedReader+StringTokenizer(the FastReader template).Scanneris fine for small inputs, but was about 4× slower at 10⁶ numbers in our measurement. - Fast output: collect lines in a
StringBuilderorPrintWriterand write once — and alwaysflush().printlnper line flushes every single time. - Budget first: ~10⁸ simple steps per second is the rule of thumb. Read n in the constraints and pick the complexity before you code.
- Verdicts are diagnoses: WA = wrong output, TLE = too slow, RE = crashed, MLE = too much memory, CE = didn't compile.
- Exceptions travel up the call stack to the nearest matching
catch; every frame in between is abandoned. The stack trace is a map to your bug. - Debug in this order: shrink the failing input → dry-run it → print to
System.error set a breakpoint →assertyour invariants (java -ea). - Test before the judge does: the samples, then edge cases you choose on purpose, then a stress test against a brute force.
04 · see it
Play with it in 3D
Press Space to play, ←/→ to step, drag to move, ? for all shortcuts. Try your own input.
How a judge runs one test
Try the submissions `off-by-one`, `crash`, `no-flush` and `slow` to see where each verdict comes from.
An exception unwinding the call stack
A bad token deep inside `parseRow` throws. Frames without a matching `catch` are discarded until `total` catches it.
Scanner vs BufferedReader, println vs one write — measured
Real timings from one desktop (JDK 26, median of 3 runs). Set your own time limit and see which bars break it.
05 · cost
Time & space, explained
| Time | Measured at n = 10⁶ | why | |
|---|---|---|---|
| Scanner.nextInt() × n | O(n) | 530 ms | Regex-based token matching through a 1,024-char buffer: a big constant factor. |
| BufferedReader + StringTokenizer + parseInt | O(n) | 140 ms | Plain character scanning through an 8,192-char buffer. |
| StreamTokenizer | O(n) | 217 ms | Fast, but parses every number as a double — exact for ints, not for longs above 2⁵³. |
| System.out.println() × n | O(n) | 2,478 ms | System.out flushes on every println: one write to the OS per line. |
| PrintWriter, flushed once | O(n) | 87 ms | Lines collect in a buffer and leave in a few large writes. |
| StringBuilder, printed once | O(n) | 48 ms | One string, one write. |
| Largest n that usually fits | why | |
|---|---|---|
| O(n!) | n ≤ 10 | 10! ≈ 3.6 × 10⁶ orders, each needing more work. |
| O(2ⁿ) | n ≤ 20 | 2²⁰ ≈ 10⁶ subsets, each needing more work. |
| O(n³) | n ≤ 500 | 500³ = 1.25 × 10⁸. |
| O(n²) | n ≤ 5,000 | 5,000² = 2.5 × 10⁷; at 10⁵ it would be 10¹⁰ — hopeless. |
| O(n log n) or O(n) | n ≤ 10⁶ | 10⁶ × 20 = 2 × 10⁷. |
| O(log n) or O(1) | any n | log₂ 10¹⁸ ≈ 60 steps. |
| Means | Usual cause in Java | why | |
|---|---|---|---|
| AC — Accepted | every test passed | — | Output matched on every hidden test, within the limits. |
| WA — Wrong Answer | ran fine, output differs | logic bug, `int` overflow, wrong format, forgot `flush()` | The program finished normally; the checker compared and disagreed. |
| TLE — Time Limit Exceeded | didn't finish in time | wrong complexity, infinite loop, Scanner/println on huge I/O | The judge stops the program at the limit, so the output is never checked. |
| RE — Runtime Error | crashed | index out of bounds, null, bad parse, StackOverflowError | An uncaught exception or a non-zero exit code. |
| MLE — Memory Limit Exceeded | used too much memory | `new int[n][n]` for big n, boxed collections | Some judges report this as a runtime error instead. |
| CE — Compile Error | didn't compile | wrong class name for the platform, missing import | Nothing ran; read the first compiler message. |
06 · java
Raw vs Collections Framework
Online-assessment input with Scanner
class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); // first token: how many numbers follow long sum = 0; // n values up to 10^9 overflow int: use long for (int i = 0; i < n; i++) sum += in.nextInt(); // any spaces or newlines between them System.out.println(sum); }}Scannerdoesn't care how numbers are split across lines —nextInt()skips any spaces and newlines.- It is simple and correct, and fine up to roughly 10⁴–10⁵ tokens. For bigger inputs, use the fast template below.
- Sum many values in a
long: 10⁵ values up to 10⁹ reach 10¹⁴, far pastint's 2,147,483,647.
The nextInt + nextLine trap
class LineTrap { static String readAgeThenName(String input) { Scanner in = new Scanner(input); int age = in.nextInt(); // reads "21" but leaves the '\n' behind String rest = in.nextLine(); // returns "" — the rest of the age line! String name = in.nextLine(); // only now the real next line return age + "|" + rest + "|" + name; } static String readAgeThenNameFixed(String input) { Scanner in = new Scanner(input); int age = Integer.parseInt(in.nextLine().trim()); // read whole lines, parse yourself String name = in.nextLine(); return age + "|" + name; }}nextInt()stops right after the digits; the line break is still waiting. The nextnextLine()returns the rest of that line: "".- Simplest fix: read whole lines with
nextLine()(orreadLine()) and parse them yourself withInteger.parseInt(line.trim()).
The fast template: BufferedReader + StringTokenizer + PrintWriter
class Main { public static void main(String[] args) throws IOException { FastReader in = new FastReader(System.in); PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out)); int n = in.nextInt(); long sum = 0; for (int i = 0; i < n; i++) sum += in.nextInt(); out.println(sum); out.flush(); // forget this and the judge sees NOTHING } /** Reads whitespace-separated tokens, whatever the line layout. */ static class FastReader { private final BufferedReader br; private StringTokenizer st; FastReader(InputStream stream) { br = new BufferedReader(new InputStreamReader(stream), 1 << 16); // 64 KB buffer } String next() throws IOException { while (st == null || !st.hasMoreTokens()) { String line = br.readLine(); if (line == null) return null; // end of input st = new StringTokenizer(line); // splits on spaces and tabs } return st.nextToken(); } int nextInt() throws IOException { return Integer.parseInt(next()); } long nextLong() throws IOException { return Long.parseLong(next()); } }}FastReader.next()refills from the next line whenever the current one runs out, so it doesn't care about line layout — numbers may be on one line or many.StringTokenizeris called a legacy class in its docs, but it's still a fast, simple way to split a line on whitespace.line.trim().split("\\s+")also works (it runs a regex).out.flush()at the end is not optional. Without it, the answer stays in the buffer and the judge sees empty output.- Need longs?
in.nextLong(). End of input?next()returnsnull.
Printing many lines
class ManyLines { static void printSquares(int n) { StringBuilder sb = new StringBuilder(); for (int i = 1; i <= n; i++) sb.append((long) i * i).append('\n'); // collect... System.out.print(sb); // ...print once }}System.outflushes on everyprintln, so 10⁶ printlns mean 10⁶ separate writes. In our measurement: 2,478 ms vs 48 ms for one StringBuilder.- Append
'\n'yourself. Judges ignore trailing spaces and the final newline, but not missing newlines between answers.
Reading until the input ends (EOF)
class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringBuilder out = new StringBuilder(); String line; while ((line = br.readLine()) != null) { // null means: no more input (EOF) line = line.trim(); if (line.isEmpty()) continue; // tolerate blank lines StringTokenizer st = new StringTokenizer(line); long a = Long.parseLong(st.nextToken()); long b = Long.parseLong(st.nextToken()); out.append(a + b).append('\n'); // one answer per input line } System.out.print(out); // one big write at the end }}readLine()returnsnullwhen there is no more input. That's your loop condition.- With Scanner the same idea is
while (in.hasNextInt()) { … }. - Testing locally in a terminal? End the input with Ctrl+Z then Enter (Windows) or Ctrl+D (Linux/macOS).
How a judge runs your code
class MiniJudge { interface Program { void run() throws Exception; } static String judge(String input, String expected, Program program, long limitMs) { InputStream realIn = System.in; PrintStream realOut = System.out; ByteArrayOutputStream captured = new ByteArrayOutputStream(); System.setIn(new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8))); // test input becomes stdin System.setOut(new PrintStream(captured, true, StandardCharsets.UTF_8)); // stdout goes into a buffer long start = System.nanoTime(); try { program.run(); // your main runs here } catch (Throwable crash) { return "RE: " + crash.getClass().getSimpleName(); // it crashed } finally { System.setIn(realIn); System.setOut(realOut); } long ms = (System.nanoTime() - start) / 1_000_000; if (ms > limitMs) return "TLE"; // a real judge kills you AT the limit String got = normalize(captured.toString(StandardCharsets.UTF_8)); return got.equals(normalize(expected)) ? "AC" : "WA"; } /** Ignores \r, spaces at line ends and blank lines at the very end — nothing else. */ static String normalize(String text) { StringBuilder sb = new StringBuilder(); for (String line : text.replace("\r", "").split("\n")) sb.append(line.stripTrailing()).append('\n'); return sb.toString().stripTrailing(); }}- LeetCode style: a hidden driver builds the arguments, calls your
Solutionmethod and compares the return value. Stdin style: the judge does what this toy does — test file onSystem.in, yourmain, capturedSystem.out, compare. - This site's stdin-mode judges work the same way: your
Main.maingets the test text onSystem.in, and spaces at line ends and blank lines at the end are ignored. Tests include everything on one line, extra spaces and Windows\r\nendings — so read tokens, never assume a line layout. - Each test is judged separately and the first failure decides the verdict. Passing the samples proves very little.
- A real judge kills your program at the time limit; this toy only measures afterwards, to keep the idea simple.
Four submissions, four verdicts
class Submissions { /** AC: read n, then n numbers on one line; print their sum. */ static void correct() throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine().trim()); StringTokenizer st = new StringTokenizer(br.readLine()); long sum = 0; for (int i = 0; i < n; i++) sum += Long.parseLong(st.nextToken()); System.out.println(sum); } /** WA: the loop stops one number early. */ static void offByOne() throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine().trim()); StringTokenizer st = new StringTokenizer(br.readLine()); long sum = 0; for (int i = 0; i < n - 1; i++) sum += Long.parseLong(st.nextToken()); System.out.println(sum); } /** RE: parses the whole line "3 9 4" as ONE number -> NumberFormatException. */ static void crash() throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); br.readLine(); // skip n System.out.println(Long.parseLong(br.readLine())); // the line has spaces in it } /** WA with the right logic: the PrintWriter is never flushed, so stdout stays empty. */ static void noFlush() throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out)); int n = Integer.parseInt(br.readLine().trim()); StringTokenizer st = new StringTokenizer(br.readLine()); long sum = 0; for (int i = 0; i < n; i++) sum += Long.parseLong(st.nextToken()); out.println(sum); // waits in the buffer... then main ends }}offByOneruns fine and prints a number — that's why WA hurts: nothing crashes to tell you.crashpasses when the line holds one number and fails when it holds several. The samples might never show it.noFlushhas perfect logic and still gets WA. The judge only sees bytes that reached stdout.
The exceptions you will actually hit
class Bugs { static int lastElement(int[] a) { return a[a.length]; // off by one -> ArrayIndexOutOfBoundsException } static char firstChar(String s) { return s.charAt(0); // s is null -> NullPointerException } // ("" -> StringIndexOutOfBoundsException) static int parse(String token) { return Integer.parseInt(token); // "12a", "", " 7" -> NumberFormatException } static int average(int sum, int count) { return sum / count; // count == 0 -> ArithmeticException: / by zero } static void removeEvens(List<Integer> list) { for (Integer x : list) { if (x % 2 == 0) list.remove(x); // changing a list while for-each walks it } // -> ConcurrentModificationException } static int depth(int n) { return 1 + depth(n + 1); // no base case -> StackOverflowError } static long[] hugeTable() { return new long[Integer.MAX_VALUE]; // ~16 GB, far past any judge's limit -> OutOfMemoryError }}ArrayIndexOutOfBoundsException/StringIndexOutOfBoundsException: an off-by-one or an empty input — checki < nand guardn == 0.NullPointerException: an object you never created (a null array slot, a missing map key unboxed intoint). Since JDK 15 the message names exactly what was null.NumberFormatException: parsing a token that isn't a clean integer — spaces, empty strings, decimals, or a number bigger thanint.ArithmeticException: / by zero: integer division or%by 0. (Double division givesInfinityinstead.)ConcurrentModificationException: you changed a list while a for-each loop walked it. UseremoveIfor anIterator.StackOverflowError/OutOfMemoryErrorareErrors, notExceptions: recursion too deep, or a table too big (new int[n][n]with n = 10⁵ is 40 GB).
How an exception travels up the stack
class Unwinding { static int total(String[] rows) { try { return sumRows(rows); } catch (NumberFormatException e) { return -1; // the exception lands here } } static int sumRows(String[] rows) { // no catch here: it just passes through int sum = 0; for (String row : rows) sum += parseRow(row); return sum; } static int parseRow(String row) { // no catch here either int s = 0; for (String token : row.split(",")) { s += Integer.parseInt(token.trim()); // "7x" -> throws } return s; }}- When
parseIntthrows, Java looks for a matchingcatchin the current method, then its caller, then its caller's caller. Methods without one simply end. - The stack trace prints that same chain, newest call first. Find the first line that names your code — the bug is usually there or one line above.
- Catch only what you can handle (bad user input, for example). In DSA practice, let bugs crash loudly — the trace is a gift.
assert and print debugging
class Tools { static int maxOf(int[] a) { assert a.length > 0 : "maxOf needs at least one element"; // checked only with java -ea int best = a[0]; for (int i = 1; i < a.length; i++) { // System.err.println("i=" + i + " a[i]=" + a[i] + " best=" + best); // print debugging if (a[i] > best) best = a[i]; } return best; } static String trace(int[] a) { StringBuilder table = new StringBuilder("i a[i] best\n"); // a dry-run table, printed int best = a[0]; for (int i = 1; i < a.length; i++) { if (a[i] > best) best = a[i]; table.append(i).append(' ').append(a[i]).append(' ').append(best).append('\n'); } return table.toString(); }}assert cond : message;runs only when the JVM starts with-ea(java -ea Main). Off by default — so never put needed work inside an assert.- Print debugging goes to
System.err, so it doesn't mix with the answer on stdout. Delete it before submitting; printing is slow. tracebuilds the dry-run table from the Mindset chapter for you: one row per iteration, one column per variable.- In an IDE, a breakpoint on the suspicious line plus the variables panel does the same job without editing code.
Your own tests: samples and edge cases
class OwnTests { static int failures = 0; static void expect(String name, int got, int want) { if (got != want) { failures++; System.err.println("FAIL " + name + ": got " + got + ", want " + want); } } static int runAll() { failures = 0; expect("the example", Tools.maxOf(new int[] {3, 9, 2}), 9); expect("single element", Tools.maxOf(new int[] {5}), 5); expect("all negative", Tools.maxOf(new int[] {-4, -2, -8}), -2); expect("max at the end", Tools.maxOf(new int[] {1, 2, 3}), 3); expect("all equal", Tools.maxOf(new int[] {7, 7, 7}), 7); expect("int limits", Tools.maxOf(new int[] {Integer.MIN_VALUE, Integer.MAX_VALUE}), Integer.MAX_VALUE); return failures; }}- Choose edge cases on purpose: one element, all equal, all negative, the answer at either end,
intlimits. - For random tests against a brute force, reuse the stress-test block in the Mindset chapter: small random inputs, a fixed seed, stop at the first mismatch.
Shrink a failing input
class Shrink { interface Bug { boolean showsOn(int[] input); } /** Drops one element at a time while the bug still shows: a big failing input becomes a tiny one. */ static int[] shrink(int[] failing, Bug bug) { int[] current = failing.clone(); boolean smaller = true; while (smaller) { smaller = false; for (int i = 0; i < current.length && !smaller; i++) { int[] candidate = without(current, i); if (bug.showsOn(candidate)) { // still broken without element i? current = candidate; // keep the smaller input and start again smaller = true; } } } return current; } static int[] without(int[] a, int skip) { int[] b = new int[a.length - 1]; for (int i = 0, j = 0; i < a.length; i++) if (i != skip) b[j++] = a[i]; return b; }}- Remove one element at a time; keep the removal if the bug still shows. Repeat until nothing more can go.
- Our example: 8 negative numbers shrink to
[-6], and the bug —beststarts at 0 — is obvious at that size. - By hand works too: delete half the input, rerun, repeat. Small failing cases explain themselves.
| call | does | cost |
|---|---|---|
new Scanner(System.in) · nextInt() / nextLong() / next() / nextLine() | Simple token and line reading | O(token), large constant |
new BufferedReader(new InputStreamReader(System.in)) · readLine() | One line at a time; null at end of input | O(line) |
new StringTokenizer(line) · nextToken() / hasMoreTokens() | Split a line on whitespace, fast | O(token) |
Integer.parseInt(s) / Long.parseLong(s) | Text → number; throws NumberFormatException | O(digits) |
new PrintWriter(new BufferedOutputStream(System.out)) · flush() | Buffered output — flush once at the end | O(total output) |
StringBuilder + System.out.print(sb) | Collect every line, print once | O(total output) |
System.err.println(x) | Debug output that stays out of stdout | slow — delete before submitting |
assert cond : "message"; | Checked only with java -ea | O(cost of cond) |
e.getMessage() / e.printStackTrace() | What went wrong, and where | — |
list.removeIf(x -> …) / iterator.remove() | Remove while iterating, safely | O(n) |
Small input, quick to write
→ Scanner
The simplest API; fast enough up to about 10⁴–10⁵ tokens.
Big input (10⁵–10⁶ tokens)
→ BufferedReader + StringTokenizer (FastReader)
About 4× faster than Scanner at 10⁶ ints in our measurement.
Many output lines
→ StringBuilder or PrintWriter, written once
println per line was ~28–52× slower at 10⁶ lines in our measurement.
Input ends without a count
→ while ((line = br.readLine()) != null)
readLine returns null at end of input.
Check an assumption while practising
→ assert + java -ea
Loud the moment it breaks; skipped when disabled.
Find the bug in a big failing input
→ Shrink it, then dry-run the small case
A 3-number failure is readable; a 10⁵-number one isn't.
07 · recognise
Spot the pattern
"Input: the first line has n, the next line has n integers"
Stdin mode: FastReader template in, StringBuilder or PrintWriter out
"Read until the end of input" / no count given
readLine() loop until it returns null
n up to 10⁵–10⁶ in the constraints
Need O(n log n) or better — and fast I/O in stdin mode
TLE, but your algorithm is O(n)
Suspect Scanner or println-per-line before the algorithm
Samples pass, WA on hidden tests
Edge cases and overflow: write them as your own tests
RE on a hidden test
Index bounds, null, parse of a bad token, recursion depth
Your output looks right but the verdict is WA
Format: missing newline between answers, extra text, forgot flush
08 · traps & tricks
Mistakes to avoid, tricks to use
traps
- Forgetting
out.flush()(orout.close()) with a PrintWriter: empty output, WA with correct logic. nextInt()followed bynextLine()returns "" — the rest of the number's line.- Scanner plus println-per-line on 10⁶ items: TLE with a perfect algorithm.
- Summing 10⁵ values up to 10⁹ in an
int: it overflows silently. Uselong. - Debug prints left on stdout: the checker compares them too. Use
System.errand delete them. - Removing from a list inside a for-each loop → ConcurrentModificationException. Use
removeIfor an Iterator. - Recursion about 10⁵ calls deep can throw StackOverflowError on a judge. Use a loop or an explicit stack.
catch (Exception e) {}that swallows everything hides the real bug — and doesn't even catch StackOverflowError.- Relying on
assertfor checks your answer needs: without-eait never runs.
tricks
- Type the FastReader template from memory once a week until it's automatic. In an OA, every minute counts.
- Read a stack trace from the top: exception and message first, then the first line that names your class — start there.
- Shrink before you stare: delete half the input, rerun, repeat.
- Before submitting: run the samples, then 3 edge cases — the smallest input, all values equal, extremes like 10⁹ and negatives.
- After two wrong answers on the same problem, stop resubmitting and dry-run on paper. Repeated WAs predict more WAs.
- Chalo, make it a ritual: samples → edge cases → stress test → submit. Calm and repeatable beats lucky.
09 · why & how
Questions you might be too shy to ask
LeetCode never asks me to read input. Why learn this?
Because LeetCode's driver does it for you. Many online assessments hand you raw stdin and an empty main instead. If you can't read input fast and correctly, you lose the round before the algorithm even matters.
How does a stdin-style online assessment judge my code?
Like the mini judge in this chapter: your main gets the test text on System.in, and what you print is compared with the expected output. Many judges forgive spaces at line ends and blank lines at the end, but check the platform's rules. Tests may put everything on one line, add extra spaces or use Windows line endings, so read tokens, not lines, and you're safe.
In stdin mode, what must my class be called?
Whatever the platform's starter code says, so read it before you type. On this site, and on many stdin judges, it is public class Main with a public static void main(String[] args). Rename it to Solution or MyCode and you can get a Compile Error even though the logic is perfect.
Why does the template say main(...) throws IOException? Do I need a try/catch?
readLine() can fail with an IOException, a checked exception: Java forces you to either catch it or declare it. Adding throws IOException to main declares it and keeps the code short. In OA code that is normal and fine; no try/catch needed.
I ran my stdin program locally and it just sits there, doing nothing. Is it stuck?
No, it is waiting for you. readLine() and nextInt() pause until input arrives on stdin. Type or paste the sample input and press Enter. If your loop reads until the end of input, finish with Ctrl+Z then Enter (Windows) or Ctrl+D (Linux/macOS).
Why is Scanner slow if it's in the standard library?
Its job is flexibility: its docs say it parses using regular expressions, and it reads through a 1,024-char buffer. BufferedReader just scans characters through an 8,192-char buffer. Same O(n), but in one rough measurement on our machine Scanner was about 4× slower at 10⁶ numbers (the exact factor varies by setup).
Is one System.out.println(answer) slow too?
No. The cost is per call: one write to the OS each time. One answer, or a few hundred lines, is nothing. In one rough measurement on our machine, 10⁶ printlns took about 2.5 s (about 2.5 µs each); your numbers will differ with the machine, the OS and where the output goes. Switch to a StringBuilder or PrintWriter once you print tens of thousands of lines or more.
Does one missing space or newline really give Wrong Answer?
Between values, yes: 1 2 and 12 are different answers, and so are two answers on one line when the judge wants one per line. What most judges forgive is extra space at the end of a line and blank lines at the very end. So print exactly the separators the statement shows, and nothing else (no "Answer:" text).
My code compiled. What does Runtime Error mean?
Compiling only proves the syntax. RE means the program crashed while running — an uncaught exception (bad index, null, bad parse, stack overflow) or a non-zero exit. The judge stops there; your output isn't even compared.
Is "10⁸ operations per second" a real number?
It's a rule of thumb, not a law. Laaksonen's Competitive Programmer's Handbook says a modern computer does "some hundreds of millions of operations" per second; judges add overhead, and Java adds JVM start-up. Use it to estimate: if your count is well above 10⁸ for a 1-second limit, find a better algorithm.
I got TLE on LeetCode. Should I switch to fast I/O?
No. On LeetCode the hidden driver reads and prints for you, so your I/O choice is not the problem. TLE there almost always means the algorithm is too slow for n (say O(n²) at n = 10⁵), or a loop that never ends. Recount your steps against the constraints first.
Debugger or print statements?
Both are fine. In an IDE, a breakpoint plus the variables panel is fastest. On an online judge, print to System.err and remove it afterwards. In a live interview, a spoken dry-run table beats both.
The judge only says Wrong Answer. How do I find the failing case?
Make your own: the samples, then edge cases you pick on purpose, then a brute-force stress test on small random inputs (the Mindset chapter has one ready). When something fails, shrink it until the bug is obvious. Bas itna yaad rakho: a small failing input is worth more than an hour of staring.
Why doesn't catch (Exception e) catch StackOverflowError?
It's an Error, not an Exception. Both extend Throwable, but the JLS describes Error as problems ordinary programs aren't expected to recover from. In DSA it simply means: recursion too deep, or (OutOfMemoryError) a table too big.
10 · practice
Interview problems
Practise this chapter on these
Each problem has one home page in the course; these use this chapter's idea too. The note says what to look for.
- #387First Unique Character in a StringEasyin Java Arrays & Strings
Submit the O(n²) version once: its 50,000-char hidden test shows you a real TLE.
- #1480Running Sum of 1d ArrayEasyin Mindset
Solve it, then rewrite it as a stdin program: read n and n numbers, print the running sums with one StringBuilder.
11 · revise
The whole chapter on one screen
8 cards, about a minute. Read them the night before an interview, or right after the chapter to lock it in.
- what it is
A judge runs your program once per test: input file → stdin → your code → stdout → checker. It only sees what you print.
- use it when
Stdin mode with 10⁵+ tokens → BufferedReader + StringTokenizer in, StringBuilder or PrintWriter out. Small input → Scanner is fine.
- template
PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));…out.println(ans); out.flush(); - cost
Rule of thumb: ~10⁸ simple steps per second. n = 10⁵: O(n²) = 10¹⁰ → TLE. O(n log n) ≈ 1.7 × 10⁶ → fine.
- trap
PrintWriter without
flush()prints nothing → WA.nextInt()thennextLine()returns "". Debug prints on stdout → WA. - pro tip
Verdicts are diagnoses: WA = output, TLE = complexity or slow I/O, RE = an exception, MLE = memory, CE = compile.
- trap
AIOOBE = bad index · NPE = null · NumberFormat = bad parse · Arithmetic = / by zero · CME = edit in for-each · StackOverflow = deep recursion.
- pro tip
Stuck on WA? Samples → edge cases → stress test vs brute force → shrink the failing input → dry-run it.
12 · recall
Flip, remember, repeat
Your PrintWriter solution prints nothing on the judge. Why?
Question 1: Your PrintWriter solution prints nothing on the judge. Why?
13 · check yourself
Quick quiz
Your PrintWriter solution prints nothing on the judge but the logic is right. What did you forget?
Input "21\nPriya". After `int age = in.nextInt();`, what does `in.nextLine()` return?
n ≤ 10⁵ and your solution is O(n²). With a 1-second limit, expect…
Your code compiled and the verdict is RE. Which is NOT a likely cause?
parseRow throws, total catches, and sumRows sits in between without a catch. What happens to sumRows?
`assert x > 0;` with x = -5, run as plain `java Main`. What happens?
14 · learn more
A second teacher, if you want one
- ✎ articleFast Input & Output ↗USACO Guide · EnglishWhy Scanner can time out on big inputs, and how BufferedReader, StringTokenizer and PrintWriter fix it. The Java templates are ready to copy.
- § docsTutorial: Debug your first Java application ↗JetBrains · IntelliJ IDEA docs · EnglishBreakpoints, stepping and watching variables, step by step. Learn it once and you can use it on every wrong answer.
- ▶ videoHow To Debug Your Code | How To Solve Any Coding Problem In Your Interview Part 3 ↗Aditya Verma · HindiHow to find your own bug calmly when there's no debugger, which is the usual situation in an interview.