Arrays
Arrays are the most fundamental data structure in programming. They store elements in contiguous memory locations, allowing constant-time access by index.
What is an Array?
An array is a collection of elements stored at contiguous memory locations. Each element can be accessed directly using its index.
Index: 0 1 2 3 4 ┌────┬────┬────┬────┬────┐Array: │ 10 │ 20 │ 30 │ 40 │ 50 │ └────┴────┴────┴────┴────┘Time Complexity
| Operation | Average | Worst |
|---|---|---|
| Access | O(1) | O(1) |
| Search | O(n) | O(n) |
| Insert (end) | O(1)* | O(n) |
| Insert (middle) | O(n) | O(n) |
| Delete | O(n) | O(n) |
*Amortized for dynamic arrays
Basic Operations
Creating and Accessing Arrays
# Creating arraysarr = [1, 2, 3, 4, 5]empty = []sized = [0] * 10 # [0, 0, 0, ..., 0]
# Accessing elementsfirst = arr[0] # 1last = arr[-1] # 5middle = arr[2] # 3
# Slicingfirst_three = arr[:3] # [1, 2, 3]last_two = arr[-2:] # [4, 5]reversed_arr = arr[::-1] # [5, 4, 3, 2, 1]
# Lengthlength = len(arr) # 5// Creating arraysconst arr = [1, 2, 3, 4, 5];const empty = [];const sized = new Array(10).fill(0);
// Accessing elementsconst first = arr[0]; // 1const last = arr[arr.length-1]; // 5const middle = arr[2]; // 3
// Slicingconst firstThree = arr.slice(0, 3); // [1, 2, 3]const lastTwo = arr.slice(-2); // [4, 5]const reversed = [...arr].reverse(); // [5, 4, 3, 2, 1]
// Lengthconst length = arr.length; // 5// Creating arraysint[] arr = {1, 2, 3, 4, 5};int[] empty = new int[0];int[] sized = new int[10]; // Filled with 0s
// Accessing elementsint first = arr[0]; // 1int last = arr[arr.length - 1]; // 5int middle = arr[2]; // 3
// Java doesn't have built-in slicing// Use Arrays.copyOfRange()int[] firstThree = Arrays.copyOfRange(arr, 0, 3);
// Lengthint length = arr.length; // 5#include <vector>#include <algorithm>using namespace std;
// Creating arraysvector<int> arr = {1, 2, 3, 4, 5};vector<int> empty;vector<int> sized(10, 0); // 10 zeros
// Accessing elementsint first = arr[0]; // 1int last = arr[arr.size()-1]; // 5int middle = arr[2]; // 3
// Slicingvector<int> firstThree(arr.begin(), arr.begin() + 3);
// Reversereverse(arr.begin(), arr.end());
// Lengthint length = arr.size(); // 5Modifying Arrays
arr = [1, 2, 3]
# Adding elementsarr.append(4) # [1, 2, 3, 4]arr.insert(0, 0) # [0, 1, 2, 3, 4]arr.extend([5, 6]) # [0, 1, 2, 3, 4, 5, 6]
# Removing elementsarr.pop() # Removes 6, returns 6arr.pop(0) # Removes 0, returns 0arr.remove(3) # Removes first occurrence of 3
# Modifyingarr[0] = 10 # Change first elementlet arr = [1, 2, 3];
// Adding elementsarr.push(4); // [1, 2, 3, 4]arr.unshift(0); // [0, 1, 2, 3, 4]arr = [...arr, 5, 6]; // [0, 1, 2, 3, 4, 5, 6]
// Removing elementsarr.pop(); // Removes 6, returns 6arr.shift(); // Removes 0, returns 0arr.splice(2, 1); // Removes element at index 2
// Modifyingarr[0] = 10; // Change first element// Use ArrayList for dynamic arraysArrayList<Integer> arr = new ArrayList<>(Arrays.asList(1, 2, 3));
// Adding elementsarr.add(4); // [1, 2, 3, 4]arr.add(0, 0); // [0, 1, 2, 3, 4]arr.addAll(Arrays.asList(5, 6));
// Removing elementsarr.remove(arr.size() - 1); // Remove lastarr.remove(0); // Remove firstarr.remove(Integer.valueOf(3)); // Remove value 3
// Modifyingarr.set(0, 10); // Change first elementvector<int> arr = {1, 2, 3};
// Adding elementsarr.push_back(4); // [1, 2, 3, 4]arr.insert(arr.begin(), 0); // [0, 1, 2, 3, 4]
// Removing elementsarr.pop_back(); // Remove lastarr.erase(arr.begin()); // Remove firstarr.erase(arr.begin() + 2); // Remove at index 2
// Modifyingarr[0] = 10; // Change first elementCommon Patterns
1. Two Pointers
Use two pointers moving towards each other or in the same direction.
def two_sum_sorted(arr, target): """Find two numbers that sum to target in sorted array""" left, right = 0, len(arr) - 1
while left < right: current_sum = arr[left] + arr[right] if current_sum == target: return [left, right] elif current_sum < target: left += 1 else: right -= 1
return [-1, -1]Learn more about Two Pointers →
2. Sliding Window
Maintain a window of elements as you iterate.
def max_sum_subarray(arr, k): """Find max sum of subarray of size k""" if len(arr) < k: return 0
# Initial window sum window_sum = sum(arr[:k]) max_sum = window_sum
# Slide the window for i in range(k, len(arr)): window_sum += arr[i] - arr[i - k] max_sum = max(max_sum, window_sum)
return max_sumLearn more about Sliding Window →
3. Prefix Sum
Precompute cumulative sums for range queries.
def build_prefix_sum(arr): """Build prefix sum array""" prefix = [0] * (len(arr) + 1) for i in range(len(arr)): prefix[i + 1] = prefix[i] + arr[i] return prefix
def range_sum(prefix, left, right): """Get sum of elements from left to right (inclusive)""" return prefix[right + 1] - prefix[left]Practice Problems
Easy
| Problem | Pattern | Companies |
|---|---|---|
| Two Sum | Hash Table | Amazon, Google, Meta |
| Best Time to Buy/Sell Stock | One Pass | Amazon, Meta |
| Contains Duplicate | Hash Set | Amazon, Apple |
| Maximum Subarray | Kadane’s | Amazon, Microsoft |
Medium
| Problem | Pattern | Companies |
|---|---|---|
| 3Sum | Two Pointers | Amazon, Google, Meta |
| Container With Most Water | Two Pointers | Amazon, Google |
| Product of Array Except Self | Prefix/Suffix | Amazon, Meta |
| Maximum Product Subarray | DP | Amazon, Microsoft |
Hard
| Problem | Pattern | Companies |
|---|---|---|
| Trapping Rain Water | Two Pointers/Stack | Amazon, Google, Meta |
| First Missing Positive | Index Marking | Amazon, Google |
| Sliding Window Maximum | Monotonic Deque | Amazon, Google |
Key Takeaways
- Arrays provide O(1) access - Use index-based access when possible
- Insertions/deletions are O(n) - Consider linked lists for frequent modifications
- Use built-in methods - They’re optimized and less error-prone
- Watch for off-by-one errors - Common source of bugs
- Consider space-time tradeoffs - Extra arrays can reduce time complexity
Next Steps
Two Pointers Master the two pointers technique for array problems
Sliding Window Learn to solve subarray problems efficiently