Data Structures & Algorithms Cheatsheet

Arrays and Strings

Use this Data Structures & Algorithms reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Complexity

A dynamic array stores elements contiguously, so indexing is O(1) and inserting in the middle shifts everything after it.

OperationArray / listNotes
index read or writeO(1)contiguous memory, cache friendly
append at endO(1) amortizeddoubling reallocation
pop from endO(1)
insert or delete at index iO(n − i)shifts the tail
insert or delete at frontO(n)use a deque instead
search unsortedO(n)
search sortedO(log n)binary search
slice of length kO(k)copies in Python and Java
reverse in placeO(n) time, O(1) space
concatenate a + bO(n + m)

Space is O(n) for the array itself, with capacity typically between n and 2n.

Python Array Toolkit

a = [3, 1, 2]
a.append(4)            # end insert, O(1) amortized
a.extend([5, 6])       # O(k)
a.insert(0, 9)         # O(n)
a.pop()                # last, O(1)
a.pop(0)               # first, O(n) -- prefer deque
a.remove(3)            # first occurrence by value, O(n)
del a[1:3]             # delete a slice
a.index(2)             # first index, ValueError if absent
a.count(2)
a.sort()               # in place, stable, O(n log n)
b = sorted(a, key=abs, reverse=True)   # new list
a.reverse()            # in place
a[::-1]                # reversed copy
a[::2]                 # every other element
sum(a), min(a), max(a), len(a)
[x * 2 for x in a if x > 1]            # comprehension
list(enumerate(a))                      # (index, value) pairs
list(zip(a, b))                         # pairwise, stops at shorter
[[0] * cols for _ in range(rows)]      # correct 2D grid

[[0] * cols] * rows aliases the same inner list rows times. Writing g[0][0] changes every row. Always use the comprehension form.

Two-Dimensional Grids

rows, cols = len(g), len(g[0])
for r in range(rows):
    for c in range(cols):
        ...

# 4-directional neighbors, bounds-checked
DIRS = ((1, 0), (-1, 0), (0, 1), (0, -1))
for dr, dc in DIRS:
    nr, nc = r + dr, c + dc
    if 0 <= nr < rows and 0 <= nc < cols:
        ...

# transpose
t = [list(row) for row in zip(*g)]

# rotate 90 degrees clockwise: transpose, then reverse each row
rot = [list(row)[::-1] for row in zip(*g)]

# flatten index math for a rows x cols grid
idx = r * cols + c
r, c = divmod(idx, cols)

In-Place Patterns

Interview arrays are usually mutated in place with O(1) extra space.

def reverse(a):
    i, j = 0, len(a) - 1
    while i < j:
        a[i], a[j] = a[j], a[i]
        i += 1
        j -= 1

def remove_val(a, val):
    """Overwrite pointer: keep everything != val, return new length."""
    k = 0
    for x in a:
        if x != val:
            a[k] = x
            k += 1
    return k

def rotate_right(a, k):
    """Reverse whole, then reverse each part. O(n) time, O(1) space."""
    n = len(a)
    k %= n
    a.reverse()
    a[:k] = reversed(a[:k])
    a[k:] = reversed(a[k:])

def dutch_flag(a):
    """Sort 0s, 1s, 2s in one pass."""
    lo, mid, hi = 0, 0, len(a) - 1
    while mid <= hi:
        if a[mid] == 0:
            a[lo], a[mid] = a[mid], a[lo]
            lo += 1
            mid += 1
        elif a[mid] == 2:
            a[mid], a[hi] = a[hi], a[mid]
            hi -= 1
        else:
            mid += 1

Strings

Strings are immutable in Python, Java, and C#, so every "modification" allocates a new string.

TaskPythonCost
build in a loopparts.append(x) then "".join(parts)O(n)
naive s += x in a loopavoidO(n²)
substrings[i:j]O(j − i)
finds.find(t), -1 if absentO(n·m) worst
containst in sO(n·m) worst
split and joins.split(","), ",".join(xs)O(n)
strips.strip(), .lstrip(), .rstrip()O(n)
cases.lower(), .upper(), .casefold()O(n)
pads.zfill(4), s.rjust(8, "0")O(n)
replaces.replace("a", "b")O(n)
tests.isalpha() .isdigit() .isalnum()O(n)
char codesord("a"), chr(97)O(1)
translates.translate(str.maketrans("ab", "xy"))O(n)
# a-z frequency without a dict
cnt = [0] * 26
for ch in s:
    cnt[ord(ch) - ord("a")] += 1

# anagram signature
from collections import Counter
Counter(s) == Counter(t)
sorted(s) == sorted(t)        # O(n log n) alternative

# palindrome check ignoring non-alphanumerics
def is_palindrome(s):
    i, j = 0, len(s) - 1
    while i < j:
        while i < j and not s[i].isalnum():
            i += 1
        while i < j and not s[j].isalnum():
            j -= 1
        if s[i].lower() != s[j].lower():
            return False
        i += 1
        j -= 1
    return True

Java And C++ Equivalents

Idioms diverge most on string building and array sizing.

// Java: StringBuilder for O(n) construction
StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()) sb.append(Character.toLowerCase(c));
String out = sb.reverse().toString();

int[] a = new int[n];                 // zero-filled, fixed length
Arrays.fill(a, -1);
Arrays.sort(a);                       // dual-pivot quicksort on primitives
int[][] g = new int[rows][cols];
List<Integer> list = new ArrayList<>();
list.add(1); list.get(0); list.size();
int[] copy = Arrays.copyOfRange(a, 1, 4);
// C++: vector plus string, both mutable and growable
vector<int> a(n, 0);
a.push_back(5);
sort(a.begin(), a.end());
reverse(a.begin(), a.end());
vector<vector<int>> g(rows, vector<int>(cols, 0));

string s = "abc";
s += 'd';                     // O(1) amortized, string is mutable here
s.substr(1, 2);               // "bc"
s.find("bc");                 // string::npos if absent

Arrays.sort on int[] in Java is quicksort and can hit O(n²) on crafted input. On Integer[] or with a comparator it is a stable merge sort. Boxing to Integer[] is the standard defense in contests.

Gotchas

  • Negative indices. Python a[-1] is the last element. Java and C++ do not wrap, a[-1] is out of bounds or undefined behavior.
  • Slice bounds never throw in Python. a[5:99] on a 3-element list returns [] rather than raising.
  • Sorting is stable in Python, Java objects, and std::stable_sort. Plain std::sort and Java primitive sort are not stable.
  • Integer division. Python // floors toward negative infinity (-7 // 2 == -4), Java and C++ truncate toward zero (-7 / 2 == -3).
  • Overflow. Java int and C++ int wrap at 2³¹ − 1. Use long for sums and lo + (hi - lo) / 2 for midpoints. Python integers are arbitrary precision.
  • Mutating while iterating a list skips elements. Iterate over a copy or build a new list.