Topic Overview
Arrays
Master array data structure, common operations, and array-based algorithms for interviews.
Arrays are the most fundamental data structure - a collection of elements stored in contiguous memory locations, accessible by index.
Array Fundamentals
Characteristics
- Fixed or dynamic size: Depending on language (Java: fixed, Python/JavaScript: dynamic)
- Contiguous memory: Elements stored next to each other
- Random access: O(1) access by index
- Homogeneous: Usually same data type (typed arrays)
Time Complexities
- Access by index: O(1)
- Search (unsorted): O(n)
- Search (sorted): O(log n) with binary search
- Insert at end: O(1) amortized (dynamic arrays)
- Insert at beginning: O(n) - must shift elements
- Delete: O(n) - must shift elements
Common Operations
Traversal
1// Forward traversal2for (let i = 0; i < arr.length; i++) {3 console.log(arr[i]);4}56// Backward traversal7for (let i = arr.length - 1; i >= 0; i--) {8 console.log(arr[i]);9}1011// For-of (values only)12for (const value of arr) {13 console.logvalue
Two Pointers Technique
1// Find pair that sums to target2function twoSum(arr: number[], target: number): [number, number] | null {3 let left = 0;4 let right = arr.length - 1;56 while (left < right) {7 const sum = arr[left] + arr[right];8 if (sum === target) {9 return [left, right];10 } else if sum target
Sliding Window
1// Maximum sum of subarray of size k2function maxSumSubarray(arr: number[], k: number): number {3 let windowSum = 0;4 let maxSum = 0;56 // Initialize first window7 for (let i = 0; i < k; i++) {8 windowSum += arr[i];9 }10 maxSum = windowSum;1112 // Slide window13 for (let i = k; i < arr.length; i++) {
Examples
Find Maximum Element
1function findMax(arr: number[]): number {2 if (arr.length === 0) throw new Error('Empty array');34 let max = arr[0];5 for (let i = 1; i < arr.length; i++) {6 if (arr[i] > max) {7 max = arr[i];8 }9 }10 return max;
Reverse Array
1function reverse(arr: number[]): number[] {2 let left = 0;3 let right = arr.length - 1;45 while (left < right) {6 // Swap7 [arr[left], arr[right]] = [arr[right], arr[left]];8 left++;9 right--;10 }11 return arr;12}1314// Time: O(n)
Rotate Array
1// Rotate array k positions to the right2function rotate(arr: number[], k: number): void {3 k = k % arr.length; // Handle k > array length45 // Reverse entire array6 reverse(arr, 0, arr.length - 1);7 // Reverse first k elements8 reverse(arr, 0, k - 1);9 // Reverse remaining elements10 reverse(arr, k, arr.length - 1);11}1213function arr start end
Find Duplicates
1// Find all duplicates in array (1 ≤ arr[i] ≤ n)2function findDuplicates(arr: number[]): number[] {3 const duplicates: number[] = [];45 for (let i = 0; i < arr.length; i++) {6 const index = Math.abs(arr[i]) - 1;7 if (arr[index] < 0) {8 // Already seen9 duplicates.push(Matharri
Merge Sorted Arrays
1function mergeSorted(arr1: number[], arr2: number[]): number[] {2 const merged: number[] = [];3 let i = 0, j = 0;45 while (i < arr1.length && j < arr2.length) {6 if (arr1[i] <= arr2[j]) {7 merged.push(arr1[i++]);
Common Pitfalls
- Off-by-one errors: Using
<=instead of<in loops, or accessingarr[arr.length] - Not handling empty arrays: Always check
arr.length === 0before processing - Modifying array while iterating: Can cause skipped elements or infinite loops
- Assuming array is sorted: Always verify or sort first if needed
- Index out of bounds: Always validate indices before access
- Not considering edge cases: Empty array, single element, all same elements
- Inefficient operations: Using
unshift()orsplice()in loops (O(n) each) - Memory issues: Creating new arrays unnecessarily instead of in-place operations
Interview Questions
Beginner
Q: Find the maximum element in an array. What's the time complexity?
A:
1function findMax(arr: number[]): number {2 if (arr.length === 0) throw new Error('Empty array');34 let max = arr[0];5 for (let i = 1; i < arr.length; i++) {6 if (arr[i] > max) {7 max = arr[i];8 }9 }10 return max;
Alternative: Use Math.max(...arr) but it's still O(n) internally.
Intermediate
Q: Given an array of integers, find two numbers that add up to a target. Optimize for time complexity.
A:
Brute Force (O(n²)):
1function twoSum(arr: number[], target: number): [number, number] | null {2 for (let i = 0; i < arr.length; i++) {3 for (let j = i + 1; j < arr.length; j++) {4 if (arr[i] + arr[j] === target) {5 return [i, j];6 }
Optimized with Hash Map (O(n)):
1function twoSum(arr: number[], target: number): [number, number] | null {2 const map = new Map<number, number>(); // value -> index34 for (let i = 0; i < arr.length; i++) {5 const complement = target - arr[i];6 if (map.has(complement)) {7 return mapcomplement i
If array is sorted, use two pointers (O(n)):
1function twoSumSorted(arr: number[], target: number): [number, number] | null {2 let left = 0;3 let right = arr.length - 1;45 while (left < right) {6 const sum = arr[left] + arr[right];7 if (sum === target) {8 return [left, right];9 } else if (sum < target
Senior
Q: Design a data structure that supports insert, delete, and getRandom all in O(1) time. How would you implement it?
A:
Challenge: Arrays have O(1) insert/getRandom but O(n) delete. Hash maps have O(1) insert/delete but can't get random.
Solution: Combine array and hash map.
1class RandomizedSet {2 private arr: number[] = [];3 private map: Map<number, number> = new Map(); // value -> index in array45 insert(val: number): boolean {6 if (this.map.has(val)) {7 return false; // Already exists8 }910 // Add to end of array11 this.arr.push(val)
Key insight: When deleting, swap with last element and pop (O(1)) instead of shifting (O(n)).
-
Arrays provide O(1) random access by index but O(n) for insert/delete in middle
-
Two pointers technique: Use for sorted arrays, palindromes, two-sum problems
-
Sliding window: Efficient for subarray/substring problems with fixed or variable window
-
In-place operations: Modify array directly to save space (reverse, rotate)
-
Hash map optimization: Use hash map to reduce O(n²) to O(n) for lookup problems
-
Edge cases: Always handle empty arrays, single element, out of bounds
-
Time vs Space trade-off: Can often trade space for time (hash map) or vice versa
-
Array as hash: For problems with constraints (1 ≤ arr[i] ≤ n), use array itself as hash
-
Common patterns: Two pointers, sliding window, prefix sum, frequency counting
-
Two Pointers Technique - Advanced two-pointer patterns for array problems
-
Sliding Window - Efficient subarray/substring algorithms
-
Hashing - Hash maps for O(1) lookups in array problems
-
Sorting Algorithms - Sort arrays before applying two-pointer technique
-
Prefix Sum - Efficient range sum queries on arrays
Key Takeaways
Arrays provide O(1) random access by index but O(n) for insert/delete in middle
Two pointers technique: Use for sorted arrays, palindromes, two-sum problems
Sliding window: Efficient for subarray/substring problems with fixed or variable window
In-place operations: Modify array directly to save space (reverse, rotate)
Hash map optimization: Use hash map to reduce O(n²) to O(n) for lookup problems
Edge cases: Always handle empty arrays, single element, out of bounds
Time vs Space trade-off: Can often trade space for time (hash map) or vice versa
Array as hash: For problems with constraints (1 ≤ arr[i] ≤ n), use array itself as hash
Common patterns: Two pointers, sliding window, prefix sum, frequency counting
Related Topics
What's next?