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.readlineandsys.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.
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)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.
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)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.
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")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.
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()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:
- 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. - Swap the data structure — a
listlistwhere you needdequedeque/setset/heapheapis often the real bottleneck, not the language. - Switch algorithm/complexity class — no I/O trick rescues an solution where was required.
- 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.
- Vectorize with libraries like array-based bulk operations, if allowed and the judge environment has them.
graph TD
A[Getting TLE] --> B{"Reading input()
line by line?"}
B -- yes --> C["Switch to sys.stdin fast-read"]
B -- no --> D{"Printing in a loop?"}
D -- yes --> E["Batch into one join + write"]
D -- no --> F{"Right Big-O for the
given constraints?"}
F -- no --> G["Fix the algorithm/data structure first"]
F -- yes --> H{"Judge offers PyPy?"}
H -- yes --> I["Submit under PyPy"]
H -- no --> J["Localize hot-loop lookups,
use built-ins, cut constant factor"]
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)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.readlineorsys.stdin.buffer.read().split()sys.stdin.buffer.read().split()remove per-line overhead.- Batch output with
"\n".join(...)"\n".join(...)+ onesys.stdout.writesys.stdout.write, don’tprintprintin 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 coffeeWas this page helpful?
Let us know how we did
