Big-O of collection operations in Java
Choosing the right collection by access pattern.
Big-O: how cost grows
Big-O describes how work grows as n grows. O(1): same cost at any size (open locker #7). O(log n): halve the search each step (dictionary lookup). O(n): look at everything (scan a list). O(n²): everything, for each thing.
The cheat sheet
Arrays jump to an index. Hash tables jump to a bucket. Balanced trees halve the search. Linked nodes walk. Deques keep both ends cheap.
ArrayList get O(1) contains O(n)
add at end amortized O(1)
LinkedList get(i) O(n)
HashSet/Map add/contains/get O(1) avg
TreeSet/Map O(log n), sorted + ranges
ArrayDeque add/remove at ends O(1)Seen it before?
You get 100,000 IDs and must check each one against all the IDs you've seen so far. ArrayList or HashSet?
Think about it, then reveal the answer
HashSet. contains on a list scans every element: O(n) per check, O(n²) total. HashSet jumps to a bucket by hash: O(1) average per check, O(n) total. At this size, that's the difference between minutes and milliseconds.
Emptying a list
A loop calls list.remove(0) on an ArrayList of n elements until it's empty. Total cost?
O(n)O(n log n)O(n²)
Show the answer
Each remove(0) shifts every remaining element left: O(n) per call, so n calls cost O(n²). ArrayDeque.pollFirst() would make each removal O(1).
Sorted and ranged? Use a tree
Need "all events between 9:00 and 10:00"? A TreeMap keeps keys sorted, so **subMap(from, to) finds the range in O(log n + k)** for k results. A HashMap would have to scan everything.
TreeMap<LocalTime, String> events = ...;
events.subMap(LocalTime.of(9, 0),
LocalTime.of(10, 0));Membership checks in a loop
List<String> seen = new ArrayList<>();
for (String id : ids) {
if (!seen.contains(id)) seen.add(id);
}contains hides a loop inside your loop.
Set<String> seen = new HashSet<>();
for (String id : ids) {
seen.add(id);
}Each add/contains is O(1) on average.
Why it matters
Collection choice is a top cause of "works on my laptop, dies in production": tests use 10 items, production uses 10 million. It's also an interview staple: expect "what's the complexity of this?" and "which collection would you use?"
Key takeaways
- ArrayList: get O(1), contains O(n), add at end amortized O(1)
- HashSet/HashMap: add, contains, get O(1) on average
- TreeSet/TreeMap: O(log n) but sorted, with range queries
- ArrayDeque: add/remove at either end O(1)
💡 Choose collections like tools: a hammer (ArrayList) is great, but not for every screw.
Big-O notation is older than computers: mathematician Paul Bachmann introduced it in 1894, and Donald Knuth popularized it in computer science in the 1970s.
Practice questions
You receive 100,000 IDs and must check, for each one, whether you've already seen it. Which collection should store the seen IDs?
- ArrayList
- HashSet
- LinkedList
- PriorityQueue
Check your answer
HashSet. HashSet's add and contains are O(1) on average, so the whole job is O(n). With a list, each contains is O(n) and the job becomes O(n²).
You store timestamped events and often ask for 'all events between 9:00 and 10:00'. Which is the best fit?
- HashMap<Instant, Event>
- TreeMap<Instant, Event>
- ArrayDeque<Event>
- HashSet<Event>
Check your answer
TreeMap<Instant, Event>. TreeMap keeps keys sorted, so subMap(from, to) returns a range in O(log n + k). A HashMap would need to scan everything.