</>CodexBash
Learn
Arrays and hashingBeginner9 min

Arrays: what is cheap and what is not

Four operations, four different costs. Knowing which is which turns most array problems from guesswork into arithmetic.

Read these first

1 of 1 still to read
  1. Where your data actually lives
An array in memorystep 1/5
1000
4
[0]
1004
9
[1]
1008
2
[2]
1012
7
[3]
1016
5
[4]

 

An array is a promise: these values sit in houses next to each other, starting at one address.

An array is the structure you will use most, so its price list is worth knowing by heart.

The price list#

what you docostwhy
read nums[i]O(1)one multiply, one add
write nums[i]O(1)same
add at the endO(1) usuallythere is normally room
insert or remove in the middleO(n)everything after it shuffles
insert or remove at the frontO(n)everything shuffles
search an unsorted arrayO(n)you have to look at all of it
search a sorted arrayO(log n)you can halve the search each time

Two of those deserve a closer look.

"Usually" constant at the end#

Adding to the end of a growable array is almost always instant, because there is spare room. When there is not, the array is copied into a bigger space, which costs O(n).

That sounds alarming until you count it properly. Each time the array fills up, its capacity doubles. Adding a million values means copying at 1, 2, 4, 8, ... up to a million, and all those copies added together come to under two million moves. Spread across a million additions, that is under two moves each.

This is called amortised constant time: any single addition might be slow, but a run of them averages out to cheap. It is why appending in a loop is fine and nobody worries about it.

Removing without shuffling#

Sometimes you do not need to keep the order. If you can live with rearrangement, removing from the middle is instant: move the last value into the gap and shorten the array by one.

[a, b, c, d, e]   remove position 1
[a, e, c, d]      e moved into b's place

One move instead of three. Worth remembering, and worth being certain the caller does not care about order.

The two pointer shape#

A great many array problems come down to walking two indexes over the same array rather than looping twice. Two common shapes:

One reading, one writing. Keep a write index that only advances when you keep a value. Removing duplicates from a sorted array and pushing zeroes to the end are both this, and both are one pass with no extra array.

One at each end, walking inward. Works when the array is sorted, or when the question is symmetric, like checking a palindrome.

Both are covered properly in their own lesson. The point here is that they cost nothing extra: no second array, and each index moves forward at most n times.

What to ask before you reach for an array#

  • Do I need to look things up by position? Array.
  • By key? Hash table.
  • Do I insert and remove in the middle constantly? Linked list, probably.
  • Do I only ever care about the largest or smallest? Heap.

Common mistakes#

  • Removing items from an array while looping forward over it. Positions shift underneath you and you skip values. Loop backwards, or build a new array, or use a write index.
  • Reaching for a nested loop when a single pass with two indexes would do.
  • Assuming an array of n values uses exactly n values' worth of memory. A growable one usually reserves spare room.

Practise it

The same idea, in the order it is worth meeting it.

  1. Not startedBuilding Pascal's triangle row by rowEasy
  2. Not startedBlank out every row and column holding a zeroMedium
  3. Not startedRunning sumEasy
  4. Not startedTurn the square a quarter turnMedium
  5. Not startedFind it by halvingEasy
  6. Not startedThe best you can take without touching neighboursMedium
  7. Not startedCombine the ranges that overlapMedium
  8. Not startedMove the zeroes to the endEasy
  9. Not startedSqueeze out the duplicatesEasy
  10. Not startedRead the grid in a spiralMedium
Create a free account to track your progress