Foundations
Arrays
Fundamentals · Starter
Complexity
| Operation | Time | Why |
|---|---|---|
Read or write arr[i] | O(1) | Direct address calculation |
Append (push) | O(1) amortised | Occasionally the block is copied to a bigger one |
Remove last (pop) | O(1) | Nothing shifts |
Insert or remove at the front (unshift, shift) | O(n) | Every later item shifts |
Insert or remove in the middle (splice) | O(n) | Items after it shift |
Search unsorted (indexOf, includes) | O(n) | Look at each item |
| Search sorted | O(log n) | Binary search |
Space is O(n).
An array stores items in one contiguous block of memory, so the position of item i is a single calculation. That is why reading arr[i] is O(1) and why almost every other structure is described by how it differs from an array.
Dynamic arrays
A JavaScript array grows on demand. Under the hood a dynamic array keeps spare capacity and, when full, allocates a block about twice as large and copies. Doubling makes the copying cost average out to O(1) per push. See the code tab for a small implementation.
JavaScript specifics
arr.sort()with no comparator sorts as strings:[10, 2, 1].sort()gives[1, 10, 2]. Usearr.sort((a, b) => a - b).sort,reverse,splice,push,pop,shiftandunshiftmutate.map,filter,slice,concatand the newertoSorted,toReversed,withreturn new arrays.new Array(3).fill([])makes three references to the same inner array. UseArray.from({ length: 3 }, () => []).arr.length = 0empties the array in place.- Copies are shallow:
[...arr]copies the top level only.
Useful methods
| Need | Use |
|---|---|
| Transform every item | map |
| Keep some items | filter |
| Fold to one value | reduce |
| First match | find, findIndex |
| Any or all match | some, every |
| Last item | arr.at(-1) |
| Flatten | flat |
| Range of numbers | Array.from({ length: n }, (_, i) => i) |
Techniques that start with an array
Most array problems are one of these patterns, each with its own page:
- Two pointers for sorted input or in-place edits.
- Sliding window for contiguous ranges.
- Prefix sums for many range queries.
- Sort first when order or neighbours matter.
- Hash map when you need "seen before?" in O(1).
Common mistakes
- Using
shift()in a loop as a queue. It is O(n) each time, so the loop is O(n²). - Mutating an array while iterating over it.
- Off-by-one on the last index: it is
length - 1.
Code
// A resizable array on top of a fixed-size block, to show why push is O(1) amortised.
export default class DynamicArray {
constructor() {
this.capacity = 2;
this.length = 0;
this.data = new Array(this.capacity);
}
get(i) {
if (i < 0 || i >= this.length) throw new RangeError('index out of range');
return this.data[i]; // O(1)
}
push(value) {
if (this.length === this.capacity) this.#grow(); // rare, O(n)
this.data[this.length++] = value; // usual case, O(1)
}
pop() {
if (this.length === 0) return undefined;
const value = this.data[--this.length];
this.data[this.length] = undefined;
return value;
}
insert(i, value) { // O(n): everything after i shifts right
if (this.length === this.capacity) this.#grow();
for (let k = this.length; k > i; k--) this.data[k] = this.data[k - 1];
this.data[i] = value;
this.length++;
}
remove(i) { // O(n): everything after i shifts left
const value = this.data[i];
for (let k = i; k < this.length - 1; k++) this.data[k] = this.data[k + 1];
this.data[--this.length] = undefined;
return value;
}
#grow() {
this.capacity *= 2;
const bigger = new Array(this.capacity);
for (let i = 0; i < this.length; i++) bigger[i] = this.data[i];
this.data = bigger;
}
}Practice
Prefix Sum
- Running Sum of 1d ArrayEasy
- Range Sum Query - ImmutableEasy
- Find Pivot IndexEasy
- Find the Highest AltitudeEasy
- Subarray Sum Equals KMedium
- Product of Array Except SelfMedium
- Continuous Subarray SumMedium
- Contiguous ArrayMedium
- Range Sum Query 2D - ImmutableMedium
- Subarray Sums Divisible by KMedium
- Maximum Size Subarray Sum Equals kMedium
- Corporate Flight BookingsMedium
- Car PoolingMedium
- Maximum SubarrayMedium
- Count of Range SumHard
Two Pointers
- Valid PalindromeEasy
- Two Sum II - Input Array Is SortedEasy
- Remove Duplicates from Sorted ArrayEasy
- Move ZeroesEasy
- Squares of a Sorted ArrayEasy
- Reverse StringEasy
- Merge Sorted ArrayEasy
- Remove ElementEasy
- 3SumMedium
- 3Sum ClosestMedium
- Container With Most WaterMedium
- Sort ColorsMedium
- Remove Duplicates from Sorted Array IIMedium
- Valid Palindrome IIMedium
- Boats to Save PeopleMedium
- Partition LabelsMedium
- 4SumMedium
- 3Sum SmallerMedium
- Trapping Rain WaterHard
Sliding Window
- Best Time to Buy and Sell StockEasy
- Maximum Average Subarray IEasy
- Contains Duplicate IIEasy
- Longest Nice SubarrayEasy
- Longest Substring Without Repeating CharactersMedium
- Longest Repeating Character ReplacementMedium
- Permutation in StringMedium
- Find All Anagrams in a StringMedium
- Minimum Size Subarray SumMedium
- Max Consecutive Ones IIIMedium
- Fruit Into BasketsMedium
- Longest Substring with At Most K Distinct CharactersMedium
- Subarray Product Less Than KMedium
- Maximum Points You Can Obtain from CardsMedium
- Count Number of Nice SubarraysMedium
- Minimum Window SubstringHard
- Sliding Window MaximumHard
- Substring with Concatenation of All WordsHard
Sort First
- Contains DuplicateEasy
- Valid AnagramEasy
- Meeting RoomsEasy
- Merge Sorted ArrayEasy
- Sort ColorsMedium
- Largest NumberMedium
- H-IndexMedium
- Wiggle Sort IIMedium
- Sort an ArrayMedium
- Custom Sort StringMedium
- Insertion Sort ListMedium
- Maximum GapHard
- Count of Smaller Numbers After SelfHard
Spotted a mistake or something unclear? Report it on GitHub.