Skip to content

Beginner: foundations · Thinking in Big-O · topic 5 of 61 · 35 min

The real cost of Python and JavaScript built-ins

Explanation

A single line of Python or JavaScript can hide a whole loop. Reading list[i] is O(1), but list.insert(0, x), list.pop(0) and x in list are O(n). Dicts, sets, Maps and Sets give O(1) lookups on average. Building a string with += in a loop can be O(n²), so collect the parts in a list and join them once.

Why built-ins matter

Interview code is short, so most of the work happens inside built-in operations. If you do not know what they cost, you cannot work out the cost of your own code. Many "time limit exceeded" errors on problem sites come from one innocent-looking line inside a loop.

Python lists, dicts and sets

OperationCostWhy
a[i], a[i] = x, len(a)O(1)Jump straight to a position
a.append(x), a.pop()O(1) amortisedWork at the end, no shifting
a.insert(0, x), a.pop(0)O(n)Every other item shifts by one place
x in a, a.index(x), a.count(x), a.remove(x)O(n)Scan the list
a[i:j]O(j − i)Slicing copies the items into a new list
sorted(a), a.sort()O(n log n)Comparison sorting
min(a), max(a), sum(a)O(n)Look at every item
d[key], key in d, d[key] = vO(1) averageHashing (Module 3)
x in s, s.add(x), s.remove(x)O(1) averageHashing
deque.appendleft(x), deque.popleft()O(1)A queue built for both ends

Dict and set operations are O(1) on average because they use hashing: the key is turned into a number that points almost straight at its slot. In rare bad cases many keys collide and it can be slower, but in practice and in interviews treat them as O(1) average.

Careful: Using a list as a queue with pop(0) makes every removal O(n). For a queue use collections.deque, whose popleft() is O(1).

Strings are immutable

Immutable means a string cannot be changed after it is made. s += "x" therefore builds a brand-new string and copies the old characters into it. In a loop that adds n pieces, the copying can add up to O(n²) work. CPython sometimes optimises this, but the Python style guide (PEP 8) says not to rely on it. The safe pattern: collect the pieces in a list, then call "".join(pieces) once, which is O(total length).

python
# Slow pattern: may copy the growing string every time
s = ""
for i in range(5):
    s += str(i) + ","

# Fast pattern: collect parts, join once
parts = []
for i in range(5):
    parts.append(str(i))
print(",".join(parts))   # Output: 0,1,2,3,4
join also puts the separator only between items, so there is no trailing comma to remove.

JavaScript arrays, Map and Set

JavaScript arrays behave like Python lists. push and pop work at the end and are O(1) amortised. shift and unshift remove or add at the front and move every other item, so treat them as O(n). includes and indexOf scan the array, O(n). The language standard does not promise exact costs, but these are what engines do in practice.

Map and Set are JavaScript's hash map and hash set, with O(1) average get, set, has and delete. A plain object can also work as a map, but its keys are always turned into strings (so 1 and "1" are the same key), and it inherits keys such as "constructor" and "toString". Use Map when keys come from user data or are not strings; Map also remembers insertion order and has a size property.

javascript
const seen = new Set();
for (const x of [3, 1, 4, 1]) {
  if (seen.has(x)) console.log('repeat:', x);
  seen.add(x);
}
console.log([10, 9, 1].sort());                 // [1, 10, 9]  (compared as strings!)
console.log([10, 9, 1].sort((a, b) => a - b));  // [1, 9, 10]
Prints repeat: 1. The default sort compares numbers as text; pass a compare function for numbers.

Common mistakes

  • x in a_list inside a loop: O(n²) in total. Fix: build a set once, then check x in the_set.
  • list.pop(0) or JavaScript shift() in a loop to process a queue. Fix: use collections.deque in Python, or keep a moving "front" index in JavaScript.
  • Building strings with += in a long loop. Fix: collect parts in a list and join once.
  • Slicing in a loop, such as a[1:] in every step. Fix: use indexes instead of copies.
  • Calling sorted() inside a loop. Fix: sort once before the loop, O(n log n) in total.
  • Using a JavaScript object as a map for arbitrary keys, or calling sort() on numbers without a compare function. Fix: use Map, and sort numbers with (a, b) => a - b.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

The real cost of Python and JavaScript built-ins · 1/8

The real cost of built-ins

This lesson shows what the everyday built-ins of Python and JavaScript really cost, so you can spot hidden loops.

Prefer a video by a teacher? Find free videos on “python list dict set time complexity big o of built in operations” on YouTube ↗

In real life: Building a bank statement export

A bank's statement page lets customers download a year of transactions as a CSV file. A first version adds each line to a string with +=; for an account with tens of thousands of transactions the export becomes noticeably slow. Collecting lines in a list and joining them once makes the export linear in the size of the file. The same team keeps the IDs of transactions already exported in a set, so checking for duplicates stays O(1) per line.

python
rows = [("2026-04-01", "UPI to Swiggy", -350), ("2026-04-02", "Salary", 52000)]
lines = ["date,description,amount"]
for date, desc, amount in rows:
    lines.append(f"{date},{desc},{amount}")
print("\n".join(lines))
Shows the CSV header and two lines. One join at the end instead of many string copies.

Practice (0/3 done)

Task 1 · Code · Python

The starter builds a string with += and also leaves a trailing comma. Rewrite format_ids(ids) so it collects the parts in a list and joins them ONCE with ",". Each id becomes "ID-" followed by the number. Example: format_ids([1, 2, 3]) returns "ID-1,ID-2,ID-3". An empty list gives "".

Task 2 · Code · Python

Write common_items(a, b) that returns a list of the items of a that also appear in b, in the order they appear in a (keep repeats from a). Make it O(n + m) by turning b into a set first, instead of checking x in b (a list) every time. Example: common_items([1, 2, 2, 3], [2, 3, 4]) returns [2, 2, 3].

Task 3 · Code · Javascript

Write firstRepeated(arr) in JavaScript. It returns the first element whose SECOND appearance comes earliest while reading left to right, or null if no element repeats. Use a Set so it runs in O(n). Example: firstRepeated([3, 1, 4, 1, 5, 3]) returns 1, because the second 1 (index 3) comes before the second 3 (index 5). Note that 1 and "1" are different values.

Quick quiz

Question 1

1.Which Python list operation is O(n)?

Question 2

2.What is the average cost of key in d for a Python dict d?

Question 3

3.Why prefer "".join(parts) over s += part in a long loop?

Question 4

4.In JavaScript, what does [10, 9, 1].sort() return?

Question 5

5.You need a queue in Python with fast removal from the front. What should you use?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which Python list operation is O(n)?

Answer: a.pop(0)

pop(0) removes the first item, so every other item shifts one place left.

What is the average cost of key in d for a Python dict d?

Answer: O(1)

Dicts use hashing, so membership is O(1) on average.

Why prefer "".join(parts) over s += part in a long loop?

Answer: s += part may copy the whole growing string each time, O(n²) in total

Strings are immutable, so += can create a new string every time; join builds the result once.

In JavaScript, what does [10, 9, 1].sort() return?

Answer: [1, 10, 9]

Without a compare function, sort compares values as strings, and "10" comes before "9".

You need a queue in Python with fast removal from the front. What should you use?

Answer: collections.deque with popleft()

deque.popleft() is O(1); list.pop(0) is O(n).

What is the average cost of checking key in d for a Python dict with n keys?Related

Answer: O(1)

Hashing jumps almost straight to the right slot, so the average cost does not grow with n.

From Hash maps and hash sets

In JavaScript, what is the usual way to avoid the O(n) cost of shift() in a queue?Related

Answer: Keep a head index that moves forward, or use a linked list

Moving an index is O(1); the used part of the array can be dropped now and then.

From Queues and deques

What is the worst-case lookup time of std::unordered_map?Related

Answer: O(n)

If many keys collide into one bucket, a lookup checks them one by one.

From std::map and std::unordered_map

Which line is valid Python?Related

Answer: ["even" if x % 2 == 0 else "odd" for x in nums]

An if-else choice goes before the for. A lone if (a filter) must go after the for.

From List, dict and set comprehensions

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Thinking in Big-O”. The module exam comes next.
  2. Module 1 exam: Thinking in Big-O · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Arrays and strings. 61 topics left in the course before the final exam.

← Previous: Best, average and worst case; analysing loops and recursion