Arrays & Strings
The most fundamental data structure in computing. Arrays store elements in contiguous memory, giving you instant O(1) index access — the bedrock of every algorithm you will ever write.
An array is a block of contiguous memory cells, each the same size.
When you write arr[i], the CPU computes
base_address + i × element_size — a single arithmetic step.
That is why access is O(1) regardless of array length.
Each cell is 4 bytes apart (32-bit int). Address of arr[i] = 0x100 + i×4.
list is a
dynamic array of pointers. Access is still O(1) (pointer lookup), but elements can be different types
and sizes because the list stores pointers, not the values directly.
base + i × size. No looping, no scanning. Instant, always.arr[:] copies the entire array in O(n) time and space.# ── Creating arrays ────────────────────────── arr = [10, 20, 30, 40, 50] arr = list(range(1, 6)) # [1, 2, 3, 4, 5] arr = [0] * 5 # [0, 0, 0, 0, 0] — fixed-size init matrix = [[0]*3 for _ in range(3)] # 3×3 2D array # ── Access & slicing ───────────────────────── x = arr[2] # O(1) → 30 last = arr[-1] # O(1) → 50 (negative indexing) sub = arr[1:4] # O(k) → [20, 30, 40] creates a copy! rev = arr[::-1] # O(n) → [50, 40, 30, 20, 10] # ── Mutations ──────────────────────────────── arr.append(60) # O(1) amortized arr.insert(0, 5) # O(n) — prepend, shifts all! arr.pop() # O(1) — remove last arr.pop(2) # O(n) — remove at index arr.remove(30) # O(n) — remove first occurrence of value # ── Searching & sorting ────────────────────── idx = arr.index(40) # O(n) linear scan arr.sort() # O(n log n) Timsort, in-place arr.sort(key=lambda x: -x) # descending # ── Useful built-ins ───────────────────────── n = len(arr) # O(1) — cached present = 30 in arr # O(n) — use set for O(1) s_arr = set(arr) # O(n) build, then O(1) lookup # ── Comprehensions ─────────────────────────── squares = [x**2 for x in arr] # O(n) evens = [x for x in arr if x % 2 == 0] # O(n) flat = [x for row in matrix for x in row] # flatten
arr.insert(0, x) slower than arr.append(x)?arr[i:j]?In Python, strings are immutable sequences of characters. Every "modification" creates a new string object. This is one of the most common sources of hidden O(n²) bugs in interview submissions.
result = ""
for char in s:
result += char # Creates a brand new string every iteration → O(n²)!
Fix: collect into a list, then "".join(chars) at the end — O(n) total.
# Strings are immutable s = "hello" s[0] = "H" # ✗ TypeError — cannot modify in place # ── Common operations ──────────────────────── s.lower() # "hello" — O(n) s.upper() # "HELLO" — O(n) s.strip() # trim whitespace — O(n) s.split(", ") # split into list — O(n) ", ".join(lst) # list → string — O(total chars) s.replace("l","x") # O(n) — new string s[::-1] # reverse — O(n) len(s) # O(1) — cached by Python # ── Efficient string building ──────────────── def build_string(s): chars = [] for ch in s: chars.append(ch.upper()) # O(1) per append return "".join(chars) # single O(n) join — correct! # ── Two-pointer palindrome check ───────────── def is_palindrome(s): l, r = 0, len(s) - 1 while l < r: if s[l] != s[r]: return False l += 1; r -= 1 return True # O(n) time, O(1) space
Most array and string interview problems reduce to one of these four patterns. Recognise the pattern → apply the template → optimise.
l and r — that move toward each other or in the same direction.
Eliminates nested loops. Best on sorted arrays or when looking for a pair satisfying some condition.
l, r = 0, len(arr) - 1
while l < r:
s = arr[l] + arr[r]
if s == target: return [l, r]
elif s < target: l += 1
else: r -= 1
# Use for: Two Sum II, 3Sum, Container With Most Water, Valid Palindrome
window = sum(arr[:k]); best = window
for i in range(k, len(arr)):
window += arr[i] - arr[i-k] # slide: add new, drop old
best = max(best, window)
return best
# Use for: Longest Substring, Min Window Substring, Max Sum Subarray
sum(arr[l:r])
answers in O(1). The key identity: sum[l:r] = prefix[r] - prefix[l].
for i, x in enumerate(arr):
prefix[i+1] = prefix[i] + x
# sum(arr[l:r]) = prefix[r] - prefix[l] → O(1) per query
# Use for: Product of Array Except Self, Range Sum Query, Subarray Sum = K
curr = best = arr[0]
for x in arr[1:]:
curr = max(x, curr + x) # extend or restart?
best = max(best, curr)
return best
# Use for: Maximum Subarray, Maximum Product Subarray, Best Time to Buy/Sell