The definitive coding interview cheat-sheet

Ressources

Interview tips

  1. Ask questions about the problem to clarify it.
  2. Don’t jump into the code, think and discuss.
  3. Don’t stay muted for a while, clarify when you are thinking, “Can I think for a second?”.
  4. Think out loud.
  5. Multiply the examples.
  6. List the corner cases.
  7. Ask for approval before coding, “Does it seem like a good strategy ?” “Should I start coding ?”

Reflexes

  1. Can sorting input data help me ?
  2. Can splitting input data help me ?
  3. Can a dictionary help me ?
  4. Can multiple pointers help me ?
  5. Can a frequency array help me ?
  6. Can multiple pass help me ?
  7. Can case-based reasoning help me ?
  8. Is there an ends here/with property ?

Tricks

Properties to look for

Strategies

Do It Yourself

Solve an example with your brain and hands and see what “algorithm” you used.

B.U.D.

Bottlenecks, Unnecessary work, Duplicated work
Walk through your best algorithm and look for these flaws.

Space/Time tradeoffs

Can I save time by using more space ?

Data Structures

Recursion

def f():
    # Base case
    ...
    # Recurisve calls
    ...

Bisection search

Bisection search ends when left and right cross.

def bisect(xs, key, f): left, right = 0, len(xs) while left < right: mid = left + (right - left) // 2 # avoid integer overflow if f(xs[mid], key): left = mid + 1 # Move right else: right = mid # Move left return left

When will they cross ?

bisect_left  = lambda xs,key: bisect(xs, key, lambda x,y: x<y)  # First occ
bisect_right = lambda xs,key: bisect(xs, key, lambda x,y: x<=y) - 1  # Last

Sorting algorithms

Merge sort

  1. Split the list in 2
  2. Recursively sort the left-most part and right-most part
  3. Merges these parts
def merge(t, i, j, k, aux): # merge t[i:k] in aux[i:k] assuming t[i:j] and t[j:k] are sorted a, b = i, j # iterators for s in range(i, k): if a == j or (b < k and t[b] < t[a]): aux[s] = t[b] b += 1 else: aux[s] = t[a] a += 1
def mergeSort(t): aux = [None] * len(t) def mergeRec(i, k): # merge sort t from i to k if k > i + 1: j = i + (k - i) // 2 mergeRec(i, j) mergeRec(j, k) merge(t, i, j, k, aux) t[i:k] = aux[i:k] mergeRec(0, len(t))

Counting sort

  1. Count the occurences of each possible values
  2. Put the number of occurence times each value in the array, starting from the smallest one
def countingSort(array, maxval): """in-place counting sort O(n + maxval)""" m = maxval + 1 # count the occurence of every possible value count = [0] * m # /!\ for a in array: count[a] += 1 i = 0 for a in range(m): for _ in range(count[a]): array[i] = a i += 1 return array

Dynamic programming

Simple steps

  1. Recursive solution
  2. Store intermediate results
  3. Bottom up (Optional)

Recursive solution

#-- 1 Naive recursive solution def f(): # Base case ... # Recurisve calls ...

Memoization

@lru_cache(maxsize=None) can automate the memoization process by using a dictionary to store the result of function calls (less efficient than an array).

#-- 2 Adding the memoization res = [[-1] * len(X) for _ in range(len(Y))] # a slot for every possible parameters # @lru_cache(maxsize=None) def f(x, y): # Base case ... # Already seen case if res[x][y] != -1: return res[x][y] # Recurisve calls ... # Just update the res[x][y] slot return res[x][y]

Bottom up

#-- 3 Bottom up def f(X, Y): res = [[-1] * len(X) for _ in range(len(Y)) for x in range(1, len(X)): # skipping dummy value for y in range(1, len(Y)): ... # update the res[x][y] slot return res[-1][-1]

int ↔ char

chr(65)   # -> 'A'
ord('A')  # -> 65
chr(97)   # -> 'a'
ord('a')  # -> 97

Base conversion

def basebTo10(x, b=2): # Horner scheme u = 0 for a in x: u = b * u + a return u def base10Tob(q, b=2): s = '' while q > 0: q, r = divmod(q, b) s = str(r) + s return s
# when our base is a power of 2 def base10ToPowOf2(q, pow=1): s = '' while q > 0 or not s: q, s = q >> pow, str(q & pow) + s return s
#-- When there is no 0 in our base # for instance counting excel columns def base10TobNoZero(q, b=2): s = '' while q > 0 or not s: q, r = divmod(q - 1, b) # -1 to remove 0 s = chr(65 + r) + s return s

Bitwise operators

Operation

Coding sets on bits

Efficient when there is less than 64 possible values

Set Binary
0
{i} 1 << i
{0,1,,n1} (1 << n) - 1
AB A | B
AB A & B
(AB)(BA) A ^ B
AB A & B == A
iA (1 << i) & A
{min(A)} -A & A

Algorithms

You should ideally now about:

(Most are overkill for an interview but nice to know as a software engineer)

Numeric/mathematical

Tree/graph

String

Sorting

Other

Links

Lot’s of info