Skip to content

Fast IO and Beating TLE

Plenty of correct, right-complexity solutions still get Time Limit Exceeded — not because the algorithm is wrong, but because reading and writing input the naive way is itself too slow when there are hundreds of thousands of lines. This page fixes that half of the TLE problem.

What you’ll learn

  • Why input()input() is slow for large inputs.
  • The two standard fast-read patterns: sys.stdin.readlinesys.stdin.readline and sys.stdin.buffer.read().split()sys.stdin.buffer.read().split().
  • Buffered output with sys.stdout.writesys.stdout.write / "\n".join"\n".join.
  • A reusable CP input template you can paste into any problem.
  • What to try when Python is genuinely too slow, beyond I/O.
  • Two silent perf traps: recursion limit and repeated attribute lookups.

Why input()input() is slow

input()input() is convenient — it prompts, reads a line, strips the trailing newline, and does encoding-safety work on every single call. That per-call overhead is invisible for 10 lines and very visible for 200,000 lines. Fast I/O in Python isn’t about a faster algorithm; it’s about paying that overhead once instead of once per line.

Pattern 1: sys.stdin.readlinesys.stdin.readline

Drop-in-ish replacement for input()input() — but it keeps the trailing newline, so you must .strip().strip() or .rstrip().rstrip() it yourself.

fast_readline.py
import sys
import io
 
# Simulate stdin so this runs standalone (a real judge already has stdin set).
sys.stdin = io.StringIO("3\napple\nbanana\ncherry\n")
 
readline = sys.stdin.readline   # local alias — see the caution below
 
n = int(readline())
words = [readline().strip() for _ in range(n)]
print(n, words)
fast_readline.py
import sys
import io
 
# Simulate stdin so this runs standalone (a real judge already has stdin set).
sys.stdin = io.StringIO("3\napple\nbanana\ncherry\n")
 
readline = sys.stdin.readline   # local alias — see the caution below
 
n = int(readline())
words = [readline().strip() for _ in range(n)]
print(n, words)

Pattern 2: read everything at once

For pure whitespace-separated tokens (most CP inputs), the fastest pattern is to read the entire input in one call and split it into a token list — one system call total, no matter how many lines follow.

fast_read_all.py
import sys
import io
 
sys.stdin = io.StringIO("4\n10 20 30 40\n")
 
data = sys.stdin.buffer.read().split()
it = iter(data)
 
n = int(next(it))
nums = [int(next(it)) for _ in range(n)]
print("n =", n, "nums =", nums)
fast_read_all.py
import sys
import io
 
sys.stdin = io.StringIO("4\n10 20 30 40\n")
 
data = sys.stdin.buffer.read().split()
it = iter(data)
 
n = int(next(it))
nums = [int(next(it)) for _ in range(n)]
print("n =", n, "nums =", nums)

sys.stdin.buffer.read()sys.stdin.buffer.read() reads raw bytes; .split().split() on bytes splits on any whitespace (spaces, newlines) and gives you a flat list of byte-strings, which int()int() happily converts.

Fast output: don’t print in a loop

print()print() inside a big loop flushes repeatedly and is surprisingly costly at scale. Build the output as a single string and write it once.

fast_output.py
import sys
 
results = [str(i * i) for i in range(10)]
 
# Slow way (fine for small n): one print() call per line
# for r in results:
#     print(r)
 
# Fast way: one join, one write
sys.stdout.write("\n".join(results) + "\n")
fast_output.py
import sys
 
results = [str(i * i) for i in range(10)]
 
# Slow way (fine for small n): one print() call per line
# for r in results:
#     print(r)
 
# Fast way: one join, one write
sys.stdout.write("\n".join(results) + "\n")

A reusable CP input template

This is the pattern to paste at the top of almost any competitive programming solution — it works whether the real judge feeds stdin, or (as here) we feed it a fake in-memory stream to run in the browser.

cp_template.py
import sys
import io
 
# --- fake stdin so this demo runs standalone; a real judge sets this for you ---
sys.stdin = io.StringIO("5\n4 2 9 1 7\n")
 
def main():
    data = sys.stdin.buffer.read().split()
    it = iter(data)
    n = int(next(it))
    arr = [int(next(it)) for _ in range(n)]
 
    out = []
    out.append(str(sum(arr)))
    out.append(str(max(arr)))
    sys.stdout.write("\n".join(out) + "\n")
 
main()
cp_template.py
import sys
import io
 
# --- fake stdin so this demo runs standalone; a real judge sets this for you ---
sys.stdin = io.StringIO("5\n4 2 9 1 7\n")
 
def main():
    data = sys.stdin.buffer.read().split()
    it = iter(data)
    n = int(next(it))
    arr = [int(next(it)) for _ in range(n)]
 
    out = []
    out.append(str(sum(arr)))
    out.append(str(max(arr)))
    sys.stdout.write("\n".join(out) + "\n")
 
main()

When Python is genuinely too slow

Sometimes fast I/O and a correct algorithm still aren’t enough — Python’s per-operation constant factor is real. In rough order of effort:

  1. Reduce the constant factor first — avoid re-computing things inside loops, localize attribute lookups (below), use built-ins (sumsum, minmin, sortedsorted) which run in C, not a Python loop.
  2. Swap the data structure — a listlist where you need dequedeque/setset/heapheap is often the real bottleneck, not the language.
  3. Switch algorithm/complexity class — no I/O trick rescues an O(n2)O(n^2) solution where O(nlogn)O(n \log n) was required.
  4. Use PyPy if the judge offers it — often a 10-50x speedup on pure-Python loops with zero code changes, because it JIT-compiles instead of interpreting.
  5. Vectorize with libraries like array-based bulk operations, if allowed and the judge environment has them.
diagram Getting TLE — what to try, in order mermaid
localize_lookups.py
import sys
sys.setrecursionlimit(10_000)
 
result = []
append = result.append   # resolve once, reuse many times
 
for i in range(10):
    append(i * i)         # faster than result.append(i * i) in a hot loop
 
print(result)
localize_lookups.py
import sys
sys.setrecursionlimit(10_000)
 
result = []
append = result.append   # resolve once, reuse many times
 
for i in range(10):
    append(i * i)         # faster than result.append(i * i) in a hot loop
 
print(result)

Practice

Drill 1 — fast-read a token stream. Fill in the blank to read all input as whitespace-separated tokens in one call.

Drill 2 — batch your output. Replace a line-by-line print loop with one joined write.

Drill 3 — localize a hot-loop lookup. Bind list.appendlist.append to a local name before the loop instead of re-resolving it every iteration.

Recap

  • input()input() is convenient but slow at scale; sys.stdin.readlinesys.stdin.readline or sys.stdin.buffer.read().split()sys.stdin.buffer.read().split() remove per-line overhead.
  • Batch output with "\n".join(...)"\n".join(...) + one sys.stdout.writesys.stdout.write, don’t printprint in a hot loop.
  • A main()main() function + read-all-tokens template is a reusable starting point for almost any CP problem.
  • If it’s still too slow: fix the algorithm/structure first, then consider PyPy, then micro-optimize (localize lookups, raise recursion limit safely).

Next: Python Idioms and Tricks for CP — the small patterns that make solutions shorter, faster, and bug-free.

If this helped you, consider buying me a coffee ☕

Buy me a coffee

Was this page helpful?

Let us know how we did