Coding Interview Cheatsheet
Arrays
Dutch Flag Partition
RED, WHITE, BLUE = range(3)
# Time: O(n)
# Space: O(1)
def dutch_flag_partition(pivot_index, A):
pivot = A[pivot_index]
# First pass: group elements smaller than pivot
smaller = 0
for i in range(len(A)):
if A[i] < pivot:
A[i], A[smaller] = A[smaller], A[i]
smaller += 1
# Second pass: group elements larger than pivot
larger = len(A) - 1
for i in range(len(A)):
if A[i] < pivot:
break
elif A[i] > pivot:
A[i], A[larger] = A[larger], A[i]
larger -= 1
Linked List
class ListNode(object):
def __init__(self, data=0, next_node=None):
self.data = data
self.next = next_node
def search_list(L, key):
while L and L.data != key:
L = L.next
return L
def insert_after(node, new_node):
new_node.next = node.next
node.next = new_node
def delete_after(node):
# Need to make sure there is something after to delete
if node.next:
node.next = node.next.next
Reverse Sublist
def reverse_sublist(L, start, finish):
dummy_head = sublist_head = ListNode(0, L)
for _ in range(1, start):
sublist_head = sublist_head.next
sublist_iter = sublist_head.next
for _ in range(finish - start):
temp = sublist_iter.next
sublist_iter.next, temp.next, sublist_head.next = (
temp.next, sublist_head.next, temp
)
return dummy_head.next
Test Cycle
def has_cycle(head):
def cycle_len(end):
start, step = end, 0
while True:
step += 1
start = start.next
if start is end:
return step
fast = slow = head
while fast and fast.next and fast.next.next:
slow, fast = slow.next, fast.next.next
if slow is fast:
it = head
for _ in range(cycle_len(slow)):
it = it.next
it2 = head
while it is not it2:
it = it.next
it2 = it2.next
return it
return None
Stacks
stack = []
stack.append(a)
stack.pop()
Building with Sunset View
def examine_buildings_with_sunset(it):
BuildingWithHeight = collections.namedtuple("BuildingWithHeight", ("id", "height"))
candidates = []
for idx, building_height in enumerate(it):
while candidates and building_height >= candidates[-1].height:
candidates.pop()
candidates.append(BuildingWithHeight(idx, building_height))
return [candidate.id for candidate in reversed(candidates)]
Queues
Queue supports 2 operations, enqueue and dequeue. Queues can be implemented with a linked list. Doubled ended queues support insertions and deletions from both ends (doubly-linked list).
collections.deque()
q.append(x)
q.appendleft(x)
q.pop()
q.popleft()
Binary Trees
Traversal
def traverse(tree):
if tree:
print(f"preorder {tree.data}")
traverse(tree.left)
print(f"inorder {tree.data}")
traverse(tree.right)
print(f"{postorder {tree.data}}")
Height Balanced
def is_balanced(tree):
BalanceStatus = collections.namedtuple("BalanceStatus", ("balanced", "height"))
def check_balanced(tree):
if not tree:
return BalanceStatus(True, -1) # Base case
left = check_balanced(tree.left)
if not left.balanced:
return BalanceStatus(False, 0)
right = check_balanced(tree.right)
if not right.balanced:
return BalanceStatus(False, 0)
is_balanced = abs(left.height - right.height) <= 1
height = max(left.height, right.height) + 1
return BalanceStatus(is_balanced, height)
return check_balanced(tree).balanced
Find Successor
Successor is leftmost element in node’s right subtree.
def successor(node):
if node.right:
node = node.right:
while node.left:
node = node.left
return node
while node.parent and node.parent.right is node:
node = node.parent
return node.parent
Heaps
Python provides min-heap via heapq
.
- \(O(\log n)\) insertions
- \(O(1)\) min element
- \(O(\log n)\) deletion of min element
heapq.heapify(L) # elements in L to heap in-place
heapq.nlargest(k, L)
heapq.nsmallest(k, L) # k largest (smallest) elements in L
heapq.heappush(h, e) # pushes new element onto heap
heapq.heappop(h) # pops smallest element from heap
heapq.heappushpop(h, a) # pushes a on heap and pops and returns smallest element
e = h[0] # return min element
Merge k sorted arrays
min_heap = []
sorted_array_iters = [iter(x) for x in sorted_arrays]
for i, it in enumerate(sorted_arrays_iters):
first_element = next(it, None)
if first_element is not None:
heapq.heappush(min_heap, (first_element, i))
result = []
while min_heap:
smallest, smallest_i = heapq.heappop(min_heap)
smallest_iter = sorted_array_iters[smallest_i]
result.append(smallest)
next_element = next(smallest_iter, None)
if next_element is not none:
heapq.heappush(min_heap, (next_element, smallest_i))
return result
Searching
def binary_search(t, A):
L, R = 0, len(A) - 1
while L <= R:
M = (L + R) // 2
if A[M] < t:
L = M + 1
elif A[M] = t:
return M
else:
R = M - 1
return -1
Sorting
class Student(object):
def __init__(self, name, gpa):
self.name = name
self.gpa = gpa
def __lt__(self, other):
return self.name < other.name
students_by_name = sorted(students)
students.sort(key = lambda: student: student.gpa) # in-place
Binary Search Trees
- \(O(\log n)\) insertion
- \(O(\log n)\) deletion
- \(O(\log n)\) lookup
- \(O(\log n)\) find
Graph
def dfs(node):
seen = {}
stack = [node]
while stack:
n = stack.pop()
for x in n.neighbours:
if x not in seen:
stack.append(s)