Introduction to Arrays
Arrays are the foundation of computer programming and one of the most fundamental data structures. Understanding arrays deeply is crucial for writing efficient code and solving complex algorithmic problems.
This comprehensive guide covers everything from basic array operations to advanced techniques used in competitive programming and technical interviews.
What Are Arrays?
An array is a contiguous block of memory that stores elements of the same data type. Each element can be accessed directly using its index, making arrays one of the most efficient data structures for random access.
Key Characteristics
- Fixed Size: In most languages, arrays have a fixed size at creation
- Contiguous Memory: Elements are stored sequentially in memory
- O(1) Access: Direct access to any element by index
- Same Type: All elements must be of the same data type
Array Operations and Time Complexity
| Operation | Time Complexity | Description |
|---|---|---|
| Access | O(1) | Direct indexing |
| Search | O(n) | Linear scan (unsorted) |
| Insert (end) | O(1)* | *Amortized for dynamic arrays |
| Insert (middle) | O(n) | Requires shifting elements |
| Delete | O(n) | Requires shifting elements |
Arrays in Different Languages
Python
# Lists in Python (dynamic arrays)
numbers = [1, 2, 3, 4, 5]
# Access
print(numbers[0]) # 1
# Slicing
print(numbers[1:4]) # [2, 3, 4]
# Common operations
numbers.append(6) # Add to end
numbers.insert(0, 0) # Insert at position
numbers.pop() # Remove last
numbers.remove(3) # Remove first occurrence of value
# List comprehension
squares = [x**2 for x in range(10)]
# Array module for fixed-type arrays
from array import array
int_array = array('i', [1, 2, 3, 4, 5])
JavaScript
// Arrays in JavaScript
const numbers = [1, 2, 3, 4, 5];
// Access
console.log(numbers[0]); // 1
// Common operations
numbers.push(6); // Add to end
numbers.unshift(0); // Add to beginning
numbers.pop(); // Remove last
numbers.shift(); // Remove first
// Functional methods
const doubled = numbers.map(x => x * 2);
const evens = numbers.filter(x => x % 2 === 0);
const sum = numbers.reduce((acc, x) => acc + x, 0);
// Spread operator
const copy = [...numbers];
const merged = [...numbers, ...otherArray];
Java
// Static array
int[] numbers = new int[5];
numbers[0] = 1;
// Array initialization
int[] nums = {1, 2, 3, 4, 5};
// ArrayList (dynamic)
ArrayList list = new ArrayList<>();
list.add(1);
list.add(2);
list.get(0);
list.remove(0);
list.size();
// Array to ArrayList
List arrayList = Arrays.asList(1, 2, 3, 4, 5);
// Stream operations
int sum = Arrays.stream(nums).sum();
int[] doubled = Arrays.stream(nums).map(x -> x * 2).toArray();
Essential Array Algorithms
1. Two Pointer Technique
def reverse_array(arr):
"""Reverse array in-place using two pointers"""
left, right = 0, len(arr) - 1
while left < right:
arr[left], arr[right] = arr[right], arr[left]
left += 1
right -= 1
return arr
def remove_duplicates_sorted(arr):
"""Remove duplicates from sorted array"""
if not arr:
return 0
write_idx = 1
for read_idx in range(1, len(arr)):
if arr[read_idx] != arr[read_idx - 1]:
arr[write_idx] = arr[read_idx]
write_idx += 1
return write_idx # New length
2. Sliding Window
def max_sum_subarray(arr, k):
"""Find maximum sum of k consecutive elements"""
if len(arr) < k:
return None
# Calculate sum of first window
window_sum = sum(arr[:k])
max_sum = window_sum
# Slide the window
for i in range(k, len(arr)):
window_sum = window_sum - arr[i - k] + arr[i]
max_sum = max(max_sum, window_sum)
return max_sum
def longest_substring_k_distinct(s, k):
"""Find longest substring with at most k distinct characters"""
char_count = {}
left = 0
max_length = 0
for right in range(len(s)):
char_count[s[right]] = char_count.get(s[right], 0) + 1
while len(char_count) > k:
char_count[s[left]] -= 1
if char_count[s[left]] == 0:
del char_count[s[left]]
left += 1
max_length = max(max_length, right - left + 1)
return max_length
3. Kadane's Algorithm (Maximum Subarray)
def max_subarray_sum(arr):
"""Find maximum sum of contiguous subarray"""
max_current = max_global = arr[0]
for i in range(1, len(arr)):
max_current = max(arr[i], max_current + arr[i])
max_global = max(max_global, max_current)
return max_global
# With indices
def max_subarray_with_indices(arr):
"""Return max sum and indices of subarray"""
max_current = arr[0]
max_global = arr[0]
start = end = s = 0
for i in range(1, len(arr)):
if arr[i] > max_current + arr[i]:
max_current = arr[i]
s = i
else:
max_current = max_current + arr[i]
if max_current > max_global:
max_global = max_current
start = s
end = i
return max_global, start, end
4. Binary Search
def binary_search(arr, target):
"""Binary search in sorted array"""
left, right = 0, len(arr) - 1
while left <= right:
mid = left + (right - left) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
def find_first_occurrence(arr, target):
"""Find first occurrence of target"""
left, right = 0, len(arr) - 1
result = -1
while left <= right:
mid = left + (right - left) // 2
if arr[mid] == target:
result = mid
right = mid - 1 # Continue searching left
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return result
5. Array Rotation
def rotate_array(arr, k):
"""Rotate array to the right by k steps"""
n = len(arr)
k = k % n # Handle k > n
# Reverse entire array
reverse(arr, 0, n - 1)
# Reverse first k elements
reverse(arr, 0, k - 1)
# Reverse remaining elements
reverse(arr, k, n - 1)
return arr
def reverse(arr, start, end):
"""Helper function to reverse array portion"""
while start < end:
arr[start], arr[end] = arr[end], arr[start]
start += 1
end -= 1
Advanced Array Techniques
Prefix Sum Array
class PrefixSum:
"""Efficient range sum queries"""
def __init__(self, arr):
self.prefix = [0]
for num in arr:
self.prefix.append(self.prefix[-1] + num)
def range_sum(self, left, right):
"""Sum of elements from left to right (inclusive)"""
return self.prefix[right + 1] - self.prefix[left]
# Usage
arr = [1, 2, 3, 4, 5]
ps = PrefixSum(arr)
print(ps.range_sum(1, 3)) # Sum of arr[1:4] = 2 + 3 + 4 = 9
Difference Array
def range_updates(n, updates):
"""Apply multiple range updates efficiently"""
diff = [0] * (n + 1)
for start, end, val in updates:
diff[start] += val
diff[end + 1] -= val
# Reconstruct array
result = [0] * n
result[0] = diff[0]
for i in range(1, n):
result[i] = result[i - 1] + diff[i]
return result
Dutch National Flag (3-way Partitioning)
def sort_colors(nums):
"""Sort array of 0s, 1s, and 2s in-place"""
low = 0
mid = 0
high = len(nums) - 1
while mid <= high:
if nums[mid] == 0:
nums[low], nums[mid] = nums[mid], nums[low]
low += 1
mid += 1
elif nums[mid] == 1:
mid += 1
else: # nums[mid] == 2
nums[mid], nums[high] = nums[high], nums[mid]
high -= 1
Common Interview Problems
1. Two Sum
def two_sum(nums, target):
"""Find two numbers that add up to target"""
seen = {}
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
return []
2. Best Time to Buy and Sell Stock
def max_profit(prices):
"""Find maximum profit from one transaction"""
if not prices:
return 0
min_price = prices[0]
max_profit = 0
for price in prices[1:]:
max_profit = max(max_profit, price - min_price)
min_price = min(min_price, price)
return max_profit
3. Product of Array Except Self
def product_except_self(nums):
"""Calculate product of all elements except self"""
n = len(nums)
result = [1] * n
# Left products
left_product = 1
for i in range(n):
result[i] = left_product
left_product *= nums[i]
# Right products
right_product = 1
for i in range(n - 1, -1, -1):
result[i] *= right_product
right_product *= nums[i]
return result
4. Container With Most Water
def max_area(height):
"""Find maximum water that can be contained"""
left = 0
right = len(height) - 1
max_water = 0
while left < right:
width = right - left
current_height = min(height[left], height[right])
max_water = max(max_water, width * current_height)
if height[left] < height[right]:
left += 1
else:
right -= 1
return max_water
Performance Optimization Tips
- Use In-Place Operations: Avoid creating new arrays when possible
- Pre-allocate Size: If size is known, pre-allocate for better performance
- Cache-Friendly Access: Access elements sequentially when possible
- Avoid Repeated Lookups: Store frequently accessed values in variables
- Use Built-in Functions: Language-specific optimizations are usually faster
Dynamic Arrays vs Static Arrays
Dynamic Arrays (ArrayList, Vector, List)
- Grow automatically when capacity is exceeded
- Amortized O(1) for append operations
- Higher memory overhead
- More flexible for unknown sizes
Static Arrays
- Fixed size at creation
- Lower memory overhead
- Slightly faster access
- Better for known-size data
Conclusion
Arrays are fundamental to programming, and mastering them is essential for every developer. From basic operations to advanced algorithms, understanding arrays deeply will improve your problem-solving skills and code efficiency.
Practice these concepts regularly, solve array-based problems, and you'll find yourself writing more efficient and elegant code.