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

  1. Use In-Place Operations: Avoid creating new arrays when possible
  2. Pre-allocate Size: If size is known, pre-allocate for better performance
  3. Cache-Friendly Access: Access elements sequentially when possible
  4. Avoid Repeated Lookups: Store frequently accessed values in variables
  5. 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.