Overview
An array stores elements in one contiguous block of memory, so the address of element i is start + i x size. That is why reading or writing arr[i] is O(1). Inserting or deleting in the middle is O(n), because every later element must shift by one position.
Strings are arrays of characters. In both JavaScript and Java they are immutable: every modification creates a new string. Most string problems reduce to counting characters, comparing positions with two pointers, or building a result efficiently with an array or StringBuilder.
You can walk straight to seat 7 because seats are numbered in order. But if someone wants to sit between seats 3 and 4, everyone from seat 4 onward has to shift one place to the right. That is O(1) access and O(n) insertion.
When to use it
- You need fast random access by index.
- Data size is known or grows mostly at the end (append is amortized O(1)).
- You want cache-friendly sequential scans, which are much faster in practice than pointer-based structures.
- Characters come from a small alphabet, so an int[26] or int[128] array can replace a hash map.
Problem patterns it solves
Recognize it when: anagrams, first unique character, can one string be built from another, character counts.
- 242. Valid Anagram
- 387. First Unique Character in a String
- 383. Ransom Note
- 2423. Remove Letter To Equalize Frequency
Recognize it when: O(1) extra space: move zeroes, remove elements, rotate array.
- 283. Move Zeroes
- 189. Rotate Array
- 27. Remove Element
Recognize it when: reverse words, reverse a segment, rotate by reversing parts.
- 151. Reverse Words in a String
- 344. Reverse String
- 58. Length of Last Word
Recognize it when: follow rules character by character: roman numerals, string to integer, compress.
- 13. Roman to Integer
- 8. String to Integer (atoi)
- 443. String Compression
- 1598. Crawler Log Folder
Recognize it when: track a best value while scanning once: max profit, consecutive runs.
- 121. Best Time to Buy and Sell Stock
- 1550. Three Consecutive Odds
- 485. Max Consecutive Ones
Where it is used in real software
Images are arrays of pixel values and audio is an array of samples. Filters and effects are loops over these arrays.
Analytics databases like ClickHouse and Parquet files store each column as a contiguous array, making scans and compression very fast.
Building JSON or HTML with repeated concatenation creates many temporary strings. Java's StringBuilder and JavaScript's array join avoid that cost.
Emojis and many scripts use more than one UTF-16 code unit, so text.length in JS or Java can differ from the number of visible characters.
Key terms
- Contiguous memory
- Elements are stored next to each other, enabling O(1) index access and fast CPU caching.
- Dynamic array
- An array that resizes (usually doubling) when full: JS arrays, Java ArrayList.
- Immutable string
- Cannot change after creation; s += c builds a new string.
- StringBuilder
- Java's mutable character buffer with amortized O(1) append.
- charCodeAt / char arithmetic
- Converting 'a'..'z' to 0..25 with c - 'a' (Java) or s.charCodeAt(i) - 97 (JS).
Core operations and their cost
- 1Access arr[i]: O(1)
Address arithmetic jumps straight to the element.
- 2Append at the end: amortized O(1)
Occasionally the array doubles and copies, but the average stays constant.
- 3Insert or delete at index i: O(n)
Elements after i must shift. In JS, splice and unshift cost O(n).
- 4Search unsorted: O(n)
Check every element. If sorted, binary search is O(log n).
- 5Build strings efficiently
Collect characters in an array (JS) or StringBuilder (Java), then join once at the end.
STEP 1Array of 5 elements with one free slot. Insert 9 at index 2.
Valid anagram with a frequency array
s = "listen", t = "silent", counts = int[26]
| Step | Character from s (+1) | Character from t (-1) | Non-zero counts |
|---|---|---|---|
| 1 | l | s | l:+1, s:-1 |
| 2 | i | i | l:+1, s:-1 |
| 3 | s | l | none |
| 4 | t | e | t:+1, e:-1 |
| 5 | e | n | t:+1, n:-1 |
| 6 | n | t | none |
NOWStep: 1 | Character from s (+1): l | Character from t (-1): s | Non-zero counts: l:+1, s:-1
All 26 counts are zero, so the strings are anagrams. O(n) time and O(1) space, because the counts array always has 26 slots regardless of n.
Implementation
// Frequency counting with a fixed array instead of a Mapfunction isAnagram(s, t) { if (s.length !== t.length) return false; const counts = new Array(26).fill(0); for (let i = 0; i < s.length; i++) { counts[s.charCodeAt(i) - 97]++; counts[t.charCodeAt(i) - 97]--; } return counts.every((c) => c === 0);} // In-place: move zeroes to the end, keep order of non-zero valuesfunction moveZeroes(nums) { let write = 0; for (let read = 0; read < nums.length; read++) { if (nums[read] !== 0) { [nums[write], nums[read]] = [nums[read], nums[write]]; write++; } }} // Rotate right by k using three reversals: O(n) time, O(1) spacefunction rotate(nums, k) { k %= nums.length; const reverse = (l, r) => { while (l < r) [nums[l++], nums[r--]] = [nums[r], nums[l]]; }; reverse(0, nums.length - 1); reverse(0, k - 1); reverse(k, nums.length - 1);} // Build strings with an array, then join oncefunction compress(chars) { const parts = []; for (let i = 0; i < chars.length; ) { let j = i; while (j < chars.length && chars[j] === chars[i]) j++; parts.push(chars[i], j - i > 1 ? String(j - i) : ""); i = j; } return parts.join("");}Complexity and performance
Direct index.
push / add at the end.
Shifting elements; splice, unshift, shift.
Unsorted / sorted with binary search.
Use StringBuilder or join.
Trade-offs
Arrays win on access and cache performance; linked lists win on O(1) insert/delete when you already hold a reference to the node.
int[26] is faster and smaller than a Map when the alphabet is known. Use a Map for Unicode or unbounded values.
In-place saves memory but mutates the caller's data. Clarify whether that is allowed.
Variants and related techniques
Track the best answer ending at the current index while scanning once (see Kadane's algorithm).
When values are in range 1..n, mark visits by negating arr[value - 1] for O(1) space duplicate detection.
Matrices are arrays of arrays; see Matrix traversal for directions, spirals, and rotation.
Common mistakes
- Using JS default sort on numbers.
Fix: [10, 9, 1].sort() gives [1, 10, 9] because it compares strings. Use sort((a, b) => a - b).
- Comparing Java strings with ==.
Fix: Use s.equals(t); == compares references.
- Concatenating strings inside a loop.
Fix: Use StringBuilder (Java) or parts.push then join (JS).
- Off-by-one at array boundaries.
Fix: Loop i < n, and check i + 1 < n before reading arr[i + 1].
- Modifying an array while iterating over it.
Fix: Use a separate write pointer, or iterate backward when deleting.
Interview questions
Why is array access O(1)?
Elements are contiguous and the same size, so the address of element i is base + i x elementSize. One arithmetic step finds it.
Why are strings immutable in Java and JavaScript?
Immutability makes strings safe to share across threads, cache their hash codes, and use as map keys. The cost is that modifications create new strings.
How would you check if two strings are anagrams in O(n)?
Count characters of one string, subtract counts for the other, and check that all counts are zero. Space is O(1) for a fixed alphabet.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| 242. Valid Anagram | Easy | Frequency array. |
| 283. Move Zeroes | Easy | Read/write pointers in place. |
| 13. Roman to Integer | Easy | Simulation with look-ahead. |
| 189. Rotate Array | Medium | Three reversals, O(1) space. |
| 238. Product of Array Except Self | Medium | Prefix and suffix products without division. |
| 49. Group Anagrams | Medium | Count signature as a map key. |