HashTo Cheet Sheet
HashTo Cheet Sheet
net
Data Structures
Arrays Strings Binary Trees
Collection of items of some data type stored one after another. A string is a sequence of characters. Many tips that apply to arrays also Is a tree like data structure where every node has at most two children.
Optimal for indexing; bad at searching, inserting, and deleting (except apply to strings. Common string algorithms: Rabin Karp (using a Trees are undirected graphs in which any two vertices are connected by
at the end). Linear arrays, Dynamic arrays, Multi dimensional arrays. rolling hash) and KMP: for searching of substring. exactly one edge and there can be no cycles in the graph.
- Neighbor: Parent or child of a node.
Things to look out for during interviews: Things to look out for during interviews: - Ancestor: A node reachable by traversing its parent chain.
- Understanding time and space complexity - Input character set and case sensitivity. (lowercase, uppercase, English - Descendant: A node in the node’s subtree.
- Knowing common array algorithms (like sorting) letters etc...) - Degree: N° of children of a node.
- Familiarity with dynamic arrays and their benefits - Degree of a tree: Maximum degree of nodes in the tree.
Techniques: Corner cases: - Distance: N° of edges along the shortest path between two nodes.
Techniques: Corner cases: - Counting characters - Empty string - Width: N° of nodes in a level.
- Sliding window - Empty sequence - String of unique characters - 1 or 2 characters - Full binary tree: Every node has exactly 0 or 2 children.
- Two pointers - Sequence with 1 or 2 elements - Anagram - Repeated characters - Perfect binary tree: Every node have 2 children.
- Traversing from the right - Sequence with repeated elements - Palindrome - Only distinct characters - Complete binary tree: All levels are fully filled, except possibly the
- Sorting the array - Duplicated values in the sequence last, with nodes as far left as possible.
- Precomputation - Balanced binary tree: Height difference between left and right
Helpful Resources:
- Index as a hash key subtrees is at most 1.
Tech Interview Handbook
- Traversing the array more than once - Level/Depth: N° of edges from the root to the node.
Python Cheat Sheet
- Height: N° of edges from its root to the furthest leaf.
- Degenerate tree: An unbalanced tree, which if entirely one-sided,
Helpful Resources: Stacks
(essentially a linked list).
Interview Cake Stores items in a last-in, first-out (LIFO). Made with linked lists/arrays.
- Number of nodes in a level 2h − 1 where h is the height of the level.
Tech Interview Handbook
Python Cheat Sheet Things to look out for during interviews:
- In-order traversal : Lef t → Root → Right :[2, 7, 5, 6, 11, 1, 9, 5, 9]
TICS - Familiarity with dynamic arrays and their benefits
- Pre-order traversal : Root → Lef t → Right :[1, 7, 2, 6, 5, 11, 9, 9, 5]
- Post-order traversal : Lef t → Right → Root :[2, 5, 11, 6, 7, 5, 9, 9, 1]
Linked List/Double Linked List
Techniques: Corner cases:
Stores data with nodes that point to other nodes. Designed to optimize - Dynamic Resizing - Popping from an empty stack Things to look out for during interviews:
insertion and deletion, slow at indexing and searching. Singly linked - Stack Reversal - Stack with one item - Sometimes interviewers ask candidates for the iterative approach.
list, Doubly linked list, Circularly linked list. - Stack with two items - Familiar with: Insert value, Delete value, Count nodes, If value is in
the tree, Calculate height
Common routines:
Helpful Resources:
- Counting the number of nodes in the linked list
Interview Cake Techniques: Corner cases:
- Reversing a linked list in-place
Tech Interview Handbook - Use recursion - Empty tree
- Finding the middle node using two pointers (fast/slow)
TICS - Algorithm Wiki - Traversing by level - Single node
- Merging two linked lists together
- Summation of nodes - Two nodes
- Very skewed tree (like a linked
Queues / Double Ended Queues
Techniques: Corner cases: list)
- Sentinel/dummy nodes - Empty linked list Stores items in a first-in, first-out (FIFO) order (Queue) or allows
- Two pointers - Single node insertion and removal from both ends (Deque).
- Using space - Two nodes Depht: 0
Helpful Resources:
- Elegant modification operations - Linked list has cycles Things to look out for during interviews:
Interview Cake
- Many languages lack efficient built-in Queues. Inform the interviewer
Tech Interview Handbook Depht: 1
Helpful Resources: and assume an efficient queue structure is available (or use deque).
TICS
Interview Cake - Deques can handle both stack and queue operations efficiently. Height: 3
Helpful Resources:
Interview Cake
Tech Interview Handbook
TICS - Algorithm Wiki
Piero24 ¯ pietrobonandrea [Link]
Binary Search Trees Hash Tables Matrices
A (BST) is a binary tree where every node’s left subtree contains only A hash map maps keys to values using a hash function to compute an A 2-dimensional array. Can be used to represent graphs where each
nodes with values less than the node’s key, and every node’s right index into an array, where the corresponding value is stored. During node is a cell on the matrix which has 4 neighbors (except those cells on
subtree contains only nodes with values greater than the node’s key. lookup, the key is hashed to find the value’s location. You likely won’t the edge and corners).
Balanced vs. Unbalanced: be asked about collision resolution in detail during interviews.
- In a balanced tree, operations are O(log n). - Separate chaining: Collided values are stored in a linked list at each Things to look out for during interviews:
- In an unbalanced tree (e.g., degenerate trees), can degrade to O(n). bucket. - Questions involving matrices are usually related to dynamic program-
Note: Some properties are the same as the one for the trees. - Open addressing: All values are stored in the array, probing for the ming or graph traversal.
next available slot when collisions occur.
- In-order traversal, Pre-order traversal, Post-order traversal: Same of Techniques: Corner cases:
those for the Binary Tree Things to look out for during interviews: - Creating an empty N x M matrix - Empty matrix
- - Transposing a matrix - 1 x 1 matrix
Things to look out for during interviews: - Only one row or column
- The same as those for the Binary Trees Techniques: Corner cases:
- How to maintain the properties after insertion and deletion - - Helpful Resources:
- Implement search, insert, and delete iteratively
Tech Interview Handbook
Helpful Resources: Apple Mango
Techniques: Corner cases: Interview Cake Avocado
- Use recursion - Empty tree Tech Interview Handbook
- Deletion, focus on understanding - Single node Python Cheat Sheet Graphs
the three different cases. - Two nodes TICS
- Balance a tree with AVL or Red- - Very skewed tree (like a linked A structure with nodes (vertices) and edges, which can be directed or
Algorithm Wiki
Black trees. list) undirected, and may have weights (a weighted graph).
- Minimum Spanning Tree: Finds the cheapest edges needed to
Trie
connect all nodes in a weighted graph.
Helpful Resources: A special tree that can compactly store strings. Be familiar with
- Directed: edges have a direction (from one node to another).
Interview Cake implementing from scratch, a Trie class and its add, remove and search
- Undirected: edges connect nodes without direction.
Tech Interview Handbook methods.
- Cyclic: Contains at least one cycle (a path that loops).
TICS
- Acyclic: No cycles.
Algorithm Wiki Things to look out for during interviews:
- Weighted: Edges have a “weight” (e.g., distance, cost, time)
- Space-efficient when storing many words with shared prefixes.
- Unweighted: Edges are simply connections between nodes.
- Efficient for prefix queries (e.g., “How many words start with. . . ”).
- Legal Coloring: Assigning colors to nodes such that no adjacent
- Often space-inefficient compared to storing strings in a set.
nodes share the same color.
- Not a standard data structure—requires custom implementation.
Heaps - Topological Sort: Orders nodes in a directed acyclic graph based on
dependencies. (e.g. scheduling tasks with prerequisites.)
A tree-based data structure that is complete and satisfies the heap
Techniques: Corner cases:
property:
- Reduces word search time from - Searching string in an empty trie Common graph representations are: Adjacency matrix, Adjacency list,
- Max heap: Each node’s val. is the largest in its subtree (recursively).
O(n) to O(k), where k is the word - Inserting empty strings into a trie Hash table of hash tables (simplest approach during interviews).
- Min heap: Each node’s val. is the smallest in its subtree (recursively).
length.
Heaps and priority queues are often treated as the same and are useful
Things to look out for during interviews:
for repeatedly removing the highest or lowest priority object with
Helpful Resources: - In interviews, graphs are often 2D matrices; ensure boundary checks
interspersed insertions. Note: Some properties are the same as the one
Interview Cake and track visited nodes.
for the trees.
Tech Interview Handbook - A tree-like diagram might be a graph with cycles, so naive recursion
can fail. Track visited nodes to avoid infinite loops.
Things to look out for during interviews:
- Be prepared to explain heap operations’ time complexities (O(log n)).
- Be aware of the space complexity for storing a heap. Graph search algorithms: Corner cases:
- Common: BFS, DFS - Empty graph
- Uncommon: Topological Sort, - Graph with one or two nodes
Techniques: Corner cases:
Dijkstra’s - Disconnected graphs
- Mention of k - Empty or Small (k = 1 - 2) heap.
- Never: Bellman-Ford, Floyd- - Graph with cycles
- Duplicate values in heaps.
Warshall, Prim’s, Kruskal’s
Helpful Resources:
Helpful Resources:
Interview Cake
Interview Cake
Tech Interview Handbook
Tech Interview Handbook
Algorithms Wiki
Piero24 ¯ pietrobonandrea [Link]
nums . append (1) # Appends 1. text . split ( ’ ’) # Splits a string into a list . from collections import deque
nums . copy () # Returns a copy of the list . l = list ( s ) # Converts a string to a list . q = deque ()
copy . deepcopy ( nums ) # A real copy of the list . message . count ( ’p ’) # Counts rep of a substring . q . append ( x ) # Enqueue x to the queue
nums . count (1) # Counts occurrences of 1. s . isnumeric () # Checks if all chars are num q . popleft () # Dequeue the front item
# Extends list with another list . message . find ( ’ fun ’) # Index of substring or -1. q [0] # Peeks at the front item
nums . extend ( otherList ) name . isalnum () # Checks if are alphanumeric . len ( q ) == 0 # Checks if the queue is empty
# Removes and returns the last item . name . isalpha () # Checks if chars are alphabets . q . appendleft ( x ) # Enqueue x to the front ( DE - Q )
nums . pop () # . pop ( index ) string . upper () # Converts to uppercase . q . pop () # Dequeue the last item ( DE - Q )
nums . reverse () # Reverses the list . string . lower () # Converts to lowercase .
nums . sort () # Sorts the list ( in place ) . string . islower () # Check if chars are lowercase . Binary Trees/Binary Search Trees
arr . insert (x , y ) # Inserts x at index y . string . isupper () # Check if chars are uppercase .
a [ start : stop ] # Slice from start to stop -1. string . isdigit () # Checks if chars are digits .
a [ -1] # Last item . txt = " aabac " # Removes leading " a ". class TreeNode :
a [:: -1] # List reversed . txt . lstrip ( " a " ) # result -> " bac " def __init__ ( self , val =0 , l = None , r = None ) :
" " . join ([ " h " , " i " ]) # O (1) , with += is O ( n ˆ2) self . val = val
Linked List/Double Linked List self . left = l
Hash Tables self . right = r
Algorithms
Binary Search DFS for Trees BFS for Graphs
Binary Search is an efficient algorithm to find an element’s position in a Depth-First Search (DFS) is a traversal algorithm that explores as far Traverses the graph level by level, starting from a given source node. It
sorted array by repeatedly dividing the search interval in half. It works down a branch as possible before backtracking. Common DFS strategies visits all neighboring nodes before moving on to nodes at the next level
on sorted sequences and has O(log n) time complexity. include pre-order, in-order, and post-order traversal for binary trees. of distance. The time complexity is O(V + E), where V is the number
The time complexity is O(V + E) where V is vertices and E is edges, of vertices and E is the number of edges.
Things to look out for during interviews: making it efficient for tree and graph traversals.
- Ensure the input is sorted (works on sorted sequences) Things to look out for during interviews:
Things to look out for during interviews: - For directed graphs, ensure edges are traversed correctly.
def binarySearch ( nums : List [ int ] , target : int ) - Choose the correct traversal type (pre-order, in-order, post-order) - For undirected graphs, mark nodes as visited to avoid revisiting.
-> int : - Commonly used for shortest path algorithms in unweighted graphs.
l , r = 0 , len ( nums ) - 1 def inorder_traversal ( self , root ) :
while l <= r : if not root : return from collections import deque
m = l + ( r - l ) // 2 inorder_traversal ( root . left ) def bfs ( root ) :
if nums [ m ] < target : print ( root . value , end = " " ) queue = deque ([ root ])
l = m + 1 inorder_traversal ( root . right ) visited = set ([ root ])
elif nums [ m ] > target :
r = m - 1 def preorder_traversal ( self , root ) : while queue :
else : if not root : return node = queue . popleft ()
return m print ( root . value , end = " " ) print ( node ) # Example operation
return -1 preorder_traversal ( root . left )
preorder_traversal ( root . right ) # Iterate over the neighbors of the node
Helpful Resources:
for neighbor in get_neighbors ( node ) :
Algorithm Wiki
def postorder_traversal ( self , root ) : # Skip already visited neighbors
Zero To Mastery
if not root : return if neighbor in visited :
postorder_traversal ( root . left ) continue
BFS for Trees
postorder_traversal ( root . right )
print ( root . value , end = " " ) queue . append ( neighbor )
Breadth-First Search (BFS) for trees traverses the tree level by level, visited . add ( neighbor )
visiting all nodes at the current depth before moving to the next level.
Helpful Resources:
It uses a queue to manage the nodes to be explored next. BFS has a
Zero To Mastery Helpful Resources:
time complexity of O(V ), where V is the number of nodes in the tree.
Algorithm Wiki Algo Master
Zero To Mastery
Things to look out for during interviews:
- Requires additional memory for the queue, which can grow large for
wide trees
Finds the shortest paths from a source node to all other nodes in a Finds the shortest path from a source node to all other nodes in a A divide-and-conquer algorithm that recursively splits the sequence in
graph, even with negative edge weights. It works by repeatedly relaxing weighted graph with non-negative edge weights. The time complexity half until each sub-sequence has one element. It then merges them back
edges and has a time complexity of O(V · E), where V is the number of is O((V + E) log V ), where V is the number of vertices and E is the together in sorted order. It is efficient for large data sets and guarantees
vertices and E is the number of edges. The algorithm can also detect number of edges. O(n log n) time complexity.
negative weight cycles.
Things to look out for during interviews: Things to look out for during interviews:
Negative edge weights in a graph can complicate the shortest path - Works only with non-negative weights. - Recursive depth and potential for stack overflow in languages without
problem, as they allow for potential decreases in path length when - Ensure priority queue or min-heap is implemented efficiently. tail recursion optimization
traversing edges. Algorithms like Dijkstra’s fail in graphs with negative - Can be adapted for shortest path in graphs with specific constraints
edge weights, but others, like Bellman-Ford, can handle them effectively. (e.g., one-to-all, all-to-all). def merge_sort ( arr : List [ int ]) -> None :
Negative weights can also lead to negative weight cycles, which can if len ( arr ) <= 1: return
result in infinitely shorter paths. import heapq
def dijkstra ( graph , n , start ) : mid = len ( arr ) // 2
Things to look out for during interviews: adj = {} left_half = arr [: mid ]
- Handles negative edge weights. for i in range (1 , n + 1) : right_half = arr [ mid :]
- Slower than Dijkstra’s algorithm. adj [ i ] = []
- Can detect negative weight cycles, which Dijkstra cannot. # Recursively sort each half
- Ensure edge relaxation is done V − 1 times for correctness. # Source , Destination , Weight left_sorted = merge_sort ( left_half )
for s , d , w in graph : right_sorted = merge_sort ( right_half )
def bellman_ford ( graph , start ) : adj [ s ] = [( d , w ) ]
# Initialize distances to all nodes as # Merge the sorted halves
infinity shortest = {} return merge ( left_sorted , right_sorted )
distances = { node : float ( ’ inf ’) for node in minHeap = [(0 , start ) ]
graph } def merge ( left : List [ int ] , right : List [ int ]) ->
distances [ start ] = 0 while minHeap : List [ int ]:
w1 , n1 = heapq . heappop ( minHeap ) sorted_array = []
# Relax edges | V | - 1 times i = j = 0
for _ in range ( len ( graph ) - 1) : if n1 in shortest :
for node in graph : continue # Merge elements from both halves in sorted
for neighbor , weight in graph [ node ]: shortest [ n1 ] = w1 order
if distances [ node ] + weight < while i < len ( left ) and j < len ( right ) :
distances [ neighbor ]: for n2 , w2 in adj [ n1 ]: if left [ i ] < right [ j ]:
distances [ neighbor ] = if n2 not in shortest : sorted_array . append ( left [ i ])
distances [ node ] + weight node = ( w2 + w1 , n2 ) i += 1
heapq . heappush ( minHeap , node ) else :
# Check for negative weight cycles return shortest sorted_array . append ( right [ j ])
for node in graph : j += 1
for neighbor , weight in graph [ node ]: Helpful Resources:
if distances [ node ] + weight < # Append remaining elements , if any
Zero To Mastery
distances [ neighbor ]: sorted_array . extend ( left [ i :])
Algorithm Wiki
print ( " Graph contains a negative sorted_array . extend ( right [ j :])
weight cycle " ) return sorted_array
return None
Helpful Resources:
return distances Algorithm Wiki
Sparse Graphs
Zero To Mastery
Helpful Resources:
Zero To Mastery
Helpful Resources:
Zero To Mastery
Zero To Mastery
Piero24 ¯ pietrobonandrea [Link]
Quick Sort Insertion Sort Bottom Up (Dynamic Programming)
A divide-and-conquer algorithm that partitions the array around a pivot Builds the sorted array one element at a time by comparing each new Technique in dynamic programming that solves subproblems first and
element, sorting elements before and after the pivot recursively. Average element with those already sorted. It’s efficient for small or nearly builds up to the final solution. It typically uses a table (usually an array
time complexity of O(n log n), (worst-case is O(n2 )) when already sorted. sorted datasets and has a time complexity of O(n2 ) in the worst case, or list) to store the results of subproblems in a bottom-up manner.
but O(n) in the best case (when the array is already sorted).
Things to look out for during interviews: Things to look out for during interviews:
- Randomize Pivot selection to improve performance Things to look out for during interviews: - Carefully define the state.
- In-place sorting but uses O(log n) stack space for recursion depth - Performs well on small or partially sorted data - Determine the base cases.
- Often used in hybrid sorting algorithms for small arrays (e.g., as part - Define how to calculate the value for a cell based on previous cells.
def quickSort ( nums : list [ int ]) -> list [ nums ]: of Timsort) - Ensure is filled in the correct order (usually iteratively).
if len ( nums ) < 2: return nums
def insertion_sort ( arr : List [ int ]) -> List [ int ]: def fib_tabulation ( n ) :
pivot = nums [0] n = len ( arr ) if n <= 1:
l , e , r = [] , [ pivot ] , [] return n
for i in range (1 , n ) : # Create list to store results of
for i in range (1 , len ( nums ) ) : key = arr [ i ] subproblems
if nums [ i ] < pivot : j = i - 1 dp = [0] * ( n + 1)
l . append ( nums [ i ]) # Define base cases
elif nums [ i ] == pivot : # Move elements of the sorted part that dp [0] , dp [1] = 0 , 1
e . append ( nums [ i ]) are greater than the key
else : # to one position ahead of their current # Fill the list using the prev results
r . append ( nums [ i ]) position for i in range (2 , n + 1) :
return quickSort ( l ) + e + quickSort ( r ) while j >= 0 and key < arr [ j ]: dp [ i ] = dp [ i - 1] + dp [ i - 2]
arr [ j + 1] = arr [ j ] return dp [ n ]
Helpful Resources:
j -= 1
Zero To Mastery Helpful Resources: AlgoMaster
# Insert the key at the correct position
Algorithm Wiki Zero To Mastery LeetCode
arr [ j + 1] = key
LeetCode Dynamic Programming GeeksforGeeks
Tech Interview Handbook
return arr
Recursion
Selection Sort
Helpful Resources:
Break problems into smaller instances of the same problem. It involves
A sorting algorithm that divides the array into sorted and unsorted Zero To Mastery
two key parts:
parts. It repeatedly selects the minimum element from the unsorted Algorithm Wiki
- A base case to stop recursion
portion and swaps it with the first unsorted element. It’s O(n2 ),
- Recursive calls to solve subproblems
inefficient for large datasets.
Finds the Minimum Spanning Tree (MST) by sorting edges and Sort an array by dividing it into several buckets, then sorting each
adding them, avoiding cycles with a union-find data structure. Time bucket individually. It’s a comparison-free sorting algorithm. Efficient
complexity: O(E log E) where E is the number of edges. for floating-point numbers. Not suitable for large input ranges.
Things to look out for during interviews: Things to look out for during interviews:
- Works well with sparse graphs (many edges) because of the sorting step. - Requires knowledge of input distribution.
- The union-find data structure is crucial for cycle detection. - Choice of bucket size affects efficiency.
- Optimize union and find with path compression and union by rank. - Optimal when input values are spread evenly.
class UnionFind :
def __init__ ( self , n ) : def bucket_sort ( arr ) :
# Initialize parent and rank arrays if len ( arr ) == 0: return arr
self . parent = list ( range ( n ) )
self . rank = [0] * n # Step 1: Create buckets
num_buckets = len ( arr )
def find ( self , u ) : max_value , min_value = max ( arr ) , min ( arr )
# Path compression : Find the root of u , bucket_range = ( max_value - min_value ) /
with path compression num_buckets
if self . parent [ u ] != u : buckets = [[] for _ in range ( num_buckets ) ]
self . parent [ u ] = self . find ( self .
parent [ u ]) # Step 2: Distribute elements into buckets
return self . parent [ u ] for num in arr :
index = int (( num - min_value ) //
def union ( self , u , v ) : bucket_range )
# Union by rank : Attach the smaller tree if index == num_buckets : # Handle edge
under the root of the larger tree case for max value
root_u = self . find ( u ) index -= 1
root_v = self . find ( v ) buckets [ index ]. append ( num )
Big-O Notaion
O(2^n)
Bad
O(n log n)
Fair
O(n)
Good Data Structure Array Sorting
O(log n), O(1)
Operation Algorithms
Excellent
Elements
Time Complexity Space Complexity Time Complexity Space Complexity
Array Θ(1) Θ(n) Θ(n) Θ(n) Θ(1) Θ(n) Θ(n) Θ(n) Θ(n) Quicksort Ω(n log(n)) Θ(n log(n)) O(n^2) O(n log(n))
Stack Θ(n) Θ(n) Θ(1) Θ(1) Θ(n) Θ(n) Θ(1) Θ(1) Θ(n) Mergesort Ω(n log(n)) Θ(n log(n)) O(n log(n)) O(n log(n))
Queue Θ(n) Θ(n) Θ(1) Θ(1) Θ(n) Θ(n) Θ(1) Θ(1) Θ(n) Timsort Ω(n) Θ(n log(n)) O(n log(n)) Θ(n)
Singly-Linked List Θ(n) Θ(n) Θ(1) Θ(1) Θ(n) Θ(n) Θ(1) Θ(1) Θ(n) Heapsort Ω(n log(n)) Θ(n log(n)) O(n log(n)) O(n log(n))
Doubly-Linked List Θ(n) Θ(n) Θ(1) Θ(1) Θ(n) Θ(n) Θ(1) Θ(1) Θ(n) Bubble Sort Ω(n) Θ(n^2) O(n^2) Θ(n)
Skip List Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(n) Θ(n) Θ(n) Θ(n) O(n log(n)) Insertion Sort Ω(n) Θ(n^2) O(n^2) Θ(n)
Hash Table N/A Θ(1) Θ(1) Θ(1) N/A Θ(n) Θ(n) Θ(n) Θ(n) Selection Sort Ω(n^2) Θ(n^2) O(n^2) Ω(n^2)
Binary Search Tree Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(n) Θ(n) Θ(n) Θ(n) Θ(n) Tree Sort Ω(n log(n)) Θ(n log(n)) O(n^2) O(n log(n))
Cartesian Tree Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) N/A Θ(n) Θ(n) Θ(n) Θ(n) Shell Sort Ω(n log(n)) Θ(n(log(n))^2) O(n(log(n))^2) O(n log(n))
B-Tree N/A Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(n) Bucket Sort Ω(n+k) Θ(n+k) O(n^2) Ω(n+k)
1 10 100
Red-Black Tree Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(n) Radix Sort Ω(n+k) Θ(n+k) Ω(n+k) Ω(n+k)
Splay Tree N/A Θ(log(n)) Θ(log(n)) Θ(log(n)) N/A Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(n) Counting Sort Ω(n+k) Θ(n+k) Ω(n+k) Ω(n+k)
AVL Tree Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(n) Cubesort Ω(n) Θ(n log(n)) O(n log(n)) O(n log(n))
KD Tree Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(log(n)) Θ(n) Θ(n) Θ(n) Θ(n) Θ(n)
Piero24 ¯ pietrobonandrea [Link]
Big-O Examples
O(1) O(n ∗ m) O(n ∗ log n)
l = m + 1
O(n2 ) else :
print ( m ) # Get all factors of n
break import math
# Traverse a square grid n = 12
nums = [[1 , 2 , 3] , [4 , 5 , 6] , [7 , 8 , 9]] # Binary Search on BST factors = set ()
for i in range ( len ( nums ) ) : def search ( root , target ) : for i in range (1 , int ( math . sqrt ( n ) ) + 1) :
for j in range ( len ( nums [ i ]) ) : if not root : if n % i == 0:
print ( nums [ i ][ j ]) return False factors . add ( i )
if target < root . val : factors . add ( n // i )
# Get every pair of elements in array return search ( root . left , target )
nums = [1 , 2 , 3] elif target > root . val : O(n!)
Solution Map
Piero24 ¯ pietrobonandrea [Link]
LeetCode Patterns
Fast & Slow Pointers Breadth First Search Sliding Window
Description: his technique uses two pointers that move at different Description: This pattern involves traversing a tree or graph level by Description: This pattern involves creating a ”window” into the data
speeds within a data structure, typically a linked list. level, visiting all nodes at each depth before moving to the next level. structure and then moving that window to gather specific information
Usage: Commonly used to detect cycles, find middle elements, or solve Usage: Useful when you need to explore nodes layer by layer in a such as finding the longest subarray containing all 1s. Sliding Windows
specific linked list problems. breadth-first manner, such as in shortest path problems or level order start from the 1st element and keep shifting right by one element and
traversals. adjust the length of the window. In some cases, the window size remains
def traverse ( head : ListNode ) -> None : constant and in other cases the sizes grows or shrinks.
if not head : return Note: You can find the code and more information in the section Usage: Primarily used in array or list-based problems, where you need
Algorithms > BFS for Graphs or Algorithms > BFS for Trees. to find a contiguous subset that satisfies certain conditions.
dummy = ListNode (0)
slow , fast = head , head Helpful Resources: Hackernoon # FIXED WINDOW
def fixed_sliding_window ( nums , k ) :
# Move fast ptr twice as fast as the slow Two Pointers window = set ()
ptr s = 0
Description: This pattern involves using two pointers that traverse a
# When the loop ends , slow will be at the
data structure from different positions, either moving toward each other
middle of the list for e in range ( len ( nums ) ) :
while fast and fast . next : or in tandem. The pointers help in efficiently narrowing down potential
if e - s + 1 > k :
slow = slow . next solutions by leveraging the structure’s ordering, such as finding pairs or
window . remove ( nums [ s ])
fast = fast . next . next triplets that satisfy a specific condition.
s += 1
Usage: Commonly used in sorted arrays or linked lists, where it’s ne-
if nums [ R ] in window :
cessary to find elements that meet certain criteria without redundant
Helpful Resources: return True
comparisons.
Hackernoon window . add ( nums [ R ])
return False
Helpful Resources:
In-place Reversal of a Linked List AlgoMaster # FLEXIBLE WINDOW
Description: This pattern involves reversing elements of a linked list Hackernoon def flexible_sliding_window ( nums , target ) :
in-place. s , tot = 0 , 0
Usage: It’s generally used when reversing a sequence without using extra Merge Intervals res = float ( " inf " )
space. Description: This pattern involves merging overlapping intervals.
for e in range ( len ( nums ) ) :
Usage: Often used in problems involving time intervals, ranges, or se-
def reverseList ( self , head : Optional [ ListNode ]) tot += nums [ e ]
quences.
-> Optional [ ListNode ]:
dummy = ListNode (0 , head ) while tot >= target :
def merge_intervals ( intervals : List [ int ]) ->
prev , curr = None , head res = min ( e - s + 1 , res )
List [ int ]:
tot , s = tot - nums [ s ] , s + 1
if not intervals : return []
while curr :
next_node = curr . next return 0 if res == float ( " inf " ) else res
intervals . sort ( key = lambda x : x [0])
curr . next = prev merged = [ intervals [0]]
prev = curr Helpful Resources:
curr = next_node for current in intervals [1:]: AlgoMaster
return prev last = merged [ -1] Hackernoon
if current [0] <= last [1]:
Helpful Resources: last [1] = max ( last [1] , current [1]) Prefix Sum
Depth First Search Helpful Resources: Usage: Primarily used to calculate the sum of any contiguous subarray
AlgoMaster (a ”range sum query”) in constant O(1) time, after an initial O(N) pre-
Description: This pattern involves traversing a tree or graph depth-
Hackernoon processing step to build the prefix sum array. This is highly effective for
wise, exploring children nodes before siblings or neighbors.
problems involving frequent sum calculations over different segments of
Usage: Useful when you need to dive deeper into a tree or graph before
an array.
exploring other paths.
Note: You can find the code and more information in the section Helpful Resources:
Algorithms > DFS for Graphs or Algorithms > DFS for Trees. AlgoMaster
Description: This pattern involves using a stack to maintain a mono- Description: This pattern utilizes two heaps (a max-heap and a min- Description: Involves exploring all possible subsets or solutions and
tonic (either entirely non-increasing or non-decreasing) order of elements. heap) to divide a set of numbers into two parts. then backtracking to correct the course whenever necessary.
Usage: It’s often used for solving problems where you need to find the Usage: It’s commonly applied in problems involving dynamic median Usage: Used for generating paths or subsets, commonly applied in prob-
next greater or smaller elements. computation or balancing tasks, such as keeping track of the smal- lems like generating all combinations, subsets, or solving puzzles.
lest/largest halves of a dataset.
def mono_stack ( insert_entries ) : def backtracking1 ( nums : List ) : # O ( n * 2ˆ n )
stack = [] import heapq subsets , curSet = [] , []
for entry in insert_entries : class MedianFinder : helper (0 , nums , curSet , subsets )
while stack and stack [ -1] <= entry : def __init__ ( self ) : return subsets
popped_item = stack . pop () self . min_heap = []
# Do something with the popped item self . max_heap = [] def helper (i , nums , curSet , subsets ) :
here if i >= len ( nums ) :
stack . append ( entry ) def add_num ( self , num : int ) -> None : subsets . append ( curSet . copy () )
# Add to max heap ( smaller half ) return
Helpful Resources: heapq . heappush ( self . max_heap , - num )
AlgoMaster
# Decision to include nums [ i ]
# Balance heaps : Ensure all elements in curSet . append ( nums [ i ])
max_heap are <= elements in min_heap helper ( i + 1 , nums , curSet , subsets )
if self . max_heap and self . min_heap and - curSet . pop () # Backtrack
self . max_heap [0] > self . min_heap [0]:
heapq . heappush ( self . min_heap , - heapq # Decision NOT to include nums [ i ]
Cyclic Sort
. heappop ( self . max_heap ) ) helper ( i + 1 , nums , curSet , subsets )
Description: In-place O(N) time, O(1) space algorithm for arrays where
values map to indices (e.g., numbers 1 to n in an array of size n). Cycles # Maintain size property : len ( max_heap ) Helpful Resources:
0<sum<6
[3,5,2]
each element nums[i] to its correct position (nums[i]-1 for 1-based) via == len ( min_heap ) or len ( max_heap ) == AlgoMaster Hackernoon
swaps until nums[i] is correct, then moves i forward. len ( min_heap ) + 1
Usage: It’s useful in situations where the data involves a finite range of if len ( self . max_heap ) > len ( self .
natural numbers (range [1, n] or [0, n-1]). min_heap ) + 1:
heapq . heappush ( self . min_heap , - heapq
def cyclic_sort ( nums : list [ int ]) -> None : . heappop ( self . max_heap ) )
i , n = 0 , len ( nums ) elif len ( self . min_heap ) > len ( self .
while i < n : max_heap ) : Backtracking (Combinations)
# Calculate index where the nums [ i ] * heapq . heappush ( self . max_heap , - heapq Description: Used to generate all combinations of size k from a set of
should * be . heappop ( self . min_heap ) ) n elements. It relies on recursive inclusion and exclusion decisions.
idx = nums [ i ] - 1 Usage: Typically used for generating subsets of fixed sizes, such as team
def find_median ( self ) -> float : selection problems or combinatorial calculations.
# Conditions before swapping : # If odd , median is the top of max_heap
# 1. Is nums [ i ] valid (1 <= x <= n ) ? if len ( self . max_heap ) > len ( self . def combinations (n , k ) : # O ( k * n ˆ2)
# 2. Is its calculated idx within the min_heap ) : combs = []
array bounds (0 to n -1) ? return - self . max_heap [0] helper (0 , [] , combs , n , k )
# 3. nums [ i ] * not * at its correct # If even , median is the average of tops return combs
position ? of both heaps
if 1 <= nums [ i ] <= n and 0 <= idx < n return ( - self . max_heap [0] + self . def helper (i , curComb , combs , n , k ) :
and nums [ i ] != nums [ idx ]: min_heap [0]) / 2 if len ( curComb ) == k :
nums [ i ] , nums [ idx ] = nums [ idx ] , nums combs . append ( curComb . copy () )
[i] Helpful Resources: return
else : Hackernoon if i > n : return
# If already correct , or it ’s out of
range or it ’s a duplicate for j in range (i , n + 1) :
i += 1 curComb . append ( j )
helper ( j + 1 , curComb , combs , n , k )
Helpful Resources: curComb . pop ()
Hackernoon
Helpful Resources:
AlgoMaster
Piero24 ¯ pietrobonandrea [Link]
Backtracking (Permutation) Top ’K’ Elements Island (Matrix Traversal)
Description: This recursive approach generates all permutations of a Description: This pattern is used to find the top ’k’ elements in a Description: Pattern for processing connected components (’islands’)
list by building permutations incrementally. Each recursive call works given dataset based on a specified criterion, such as frequency, value, or of cells with a specific in a 2D grid, often surrounded by another value .
on the next element and inserts it into all possible positions of the exist- priority. It is often implemented using sorting techniques or heap data Uses Depth-First Search (DFS) or Breadth-First Search (BFS) for graphs
ing permutations. structures to optimize for time complexity. to explore all parts of an island once its first cell is discovered.
Usage: Commonly used in problems requiring all possible arrangements Usage: Solve problems requiring partial sorting or selective extraction. Usage: It’s generally used in grid-based problems, especially when we
of elements in a list, such as scheduling, generating anagrams, or solving Max-Heap/Min-Heap efficiently maintain the top ’k’ elements. need to group connected elements together
puzzles.
Note: You can find the code and more information in the section
def permutationsRecursive ( nums ) : # O ( n ˆ2 * n !) import heapq Algorithms > DFS for Graphs or Algorithms > BFS for Graphs.
return helper (0 , nums ) from collections import Counter
Helpful Resources:
Helpful Resources:
AlgoMaster
AlgoMaster
Hackernoon
Hackernoon
Piero24 ¯ pietrobonandrea [Link]
Bitwise XOR Union Find
Description: This pattern involves the use of Bitwise XOR to solve Description: Union Find, also known as Disjoint Set Union (DSU), is
various array-based problems. a data structure that partitions a set into disjoint subsets and supports
Usage: It’s used when we need to manipulate and compare bits directly. two key operations efficiently:
1. Union: Merge two subsets into one.
# Example 1: Find the single number in an array 2. Find: Determine the root or representative element of a subset.
where every element appears twice except one Usage: Solve problems related to connectivity in graphs, such as de-
. tecting cycles, finding connected components, and checking if two nodes
def find_single_number ( nums ) : belong to the same set.
result = 0
for num in nums : class UnionFind :
result ˆ= num # XOR operation def __init__ ( self , n ) :
return result self . par = (}
self . rank = {}
for i in range (1 , n + 1) :
self . par [ i ] = i
self . rank [ i ] = 0
Topological Sort (Graph)
def find ( self , n ) :
Description: A linear ordering of vertices in a directed acyclic graph
p = self . par ( n ]
(DAG), such that for every directed edge (u, v), vertex u appears before while p != self . par [ p ]:
v in the ordering. self . par [ p ] = self . par [ self . par [ p ]]
Usage: Solve problems involving scheduling, dependency resolution, and p = self . par ( p ]
precedence constraints. return p
Things to Watch:
- Graph must be a DAG for a valid topological sort. def union ( self , x , y ) :
- Handle nodes with multiple dependencies. p1 , p2 = self . find ( x ) , self . find ( y )
- Use Kahn’s algorithm (BFS) or DFS for implementation. if p1 == p2 :
return False
def find_indegree ( graph ) :
indegree = { node :0 for node in graph } if self . rank [ p1 ] > self . rank [ p2 ]:
for node in graph : self . par [ p2 ]= p1
for neighbor in graph [ node ]: elif self . rank [ p1 ] < self . rank [ p2 ]:
indgree [ neighbor ] += 1 self . par [ p1 ] = p2
return indegree else :
self . par [ p1 ] = p2
self . rank [ p2 ] += 1
def topological_sort ( graph ) : return True
q , res = deque () , []
indegree = find_indegree ( graph )
for node in indegree :
if indegree [ node ] == 0:
q . append ( node )
while len ( q ) > 0:
node = q . popleft ()
res . append ( node )
for neighbor in graph [ node ]:
indegree [ neighbor ] -= 1
if indegree [ neighbor ] == 0:
q . append ( neighbor )
return res if len ( graph ) == len ( res ) else
None
Helpful Resources:
Hackernoon
Piero24 ¯ pietrobonandrea [Link]
Other
Binary Math Extra Methods
Binary is a base-2 number system that represents values using two Mathematics is foundational in Computer Science, and all programmers
symbols: 0 and 1. Each position represents a power of 2, with the should possess basic mathematical knowledge. map ( func , iter ) # Applies a function to each
rightmost digit representing 20 , the next 21 , and so on. item in the iterable Example : map ( str , [1 ,
Things to look out for during interviews: 2 , 3]) = > [ ’1 ’ , ’2 ’ , ’3 ’]
Things to look out for during interviews: - Division/Modulo: Always check for division or modulo by zero
- Questions involving binary representations and bitwise operations - Overflow/Underflow: Languages like Java or C++, acknowledge the zip ( list1 , list2 ) # Combines two lists into
- Convert from decimal into binary (and vice versa) potential for overflow/underflow and ask if it needs to be handled tuples , stops at shortest list Example : a =
- Negative/Floating Point Numbers: Don’t overlook these cases (" John " , " Charles ") , b = (" Jenny " , " Monica ")
Technique Code zip (a , b ) = > [( ’ John ’, ’ Jenny ’) , ( ’ Charles
Test if k-th bit is set num & (1 << k) != 0 Formula ’, ’ Monica ’) ]
Set k-th bit num |= (1 >> k) Check if a number is even num % 2 == 0
(N +1)·N any ( list ) # True an element is true
Turn off k-th bit num &= ∼(1 << k) Sum of 1 to N 1 + 2 + ... + N = 2
Toggle the k-th bit num ˆ= (1 << k) Sum of Geometric Progr. 20 + 21 + . . . + 2n = 2n+1 − 1 all ( list ) # True all elements are true
N!
Multiply by 2k num << k Permutations of N (N −K)!
enumerate ( list | tuple ) # Adds index to list
Divide by 2k num >> k Combinations of N N!
K!·(N −K)! elements Example : [ ’ a ’, ’b ’] = > [(0 , ’a ’) ,
Check if a number is a (num & (num - 1)) == 0 or (num Fibonacci Sequence F (n) = F (n − 1) + F (n − 2), F (0) =
(1 , ’b ’) ]
power of 2 & (-num)) == num 0, F (1) = 1
filter ( func , list ) # Filters elements that
Swapping two variables num1 ˆ= num2; num2 ˆ= num1;
return true from func
num1 ˆ= num2
Techniques: Corner cases:
- Multiples of a number - Division by 0 import bisect
Corner cases:
- Comparing floats - Multiplication by 1 bisect . bisect ( list , num ) # Returns index to
- Check for overflow/underflow
- Fast operators - Negative numbers insert num to maintain sort O ( log ( n ) )
- Negative numbers
- Floats
bisect . bisect_left () # Insert at left of
Helpful Resources:
existing
# AND # OR bisect . bisect_right () # Insert at right of
n = 1 & 1 n = 1 | 0 Tech Interview Handbook
existing
# XOR # NOT ( negation ) bisect . insort ( list , num ) # Inserts num and
Intervals
n = 0ˆ1 n = ˜n returns sorted list
n = 1 n = n << 1 n = n >> 1 # Bit shifting Interval questions involve an array of two-element arrays (intervals),
where each represents a start and end value, e.g., [[1, 2], [4, 7]]. These ord ( char ) # Returns ASCII value , ord ( ’ a ’) = 97
Helpful Resources: questions can be tricky due to various overlapping cases. chr ( num ) # Returns char from ASCII , chr (97) = ’a ’
Tech Interview Handbook
Things to look out for during interviews: nonlocal val # Refers to a variable in the
Sorting - Are [1, 2] and [2, 3] considered overlapping? nearest enclosing scope that is not global .
- Does [a, b] strictly follow a < b? Used in nested functions to modify a
Sorting rearranges elements in a sequence (numerical or lexicograph-
variable in the outer function
ical) in ascending or descending order. Avoid O(n²) algorithms in
interviews; use your language’s default sorting function for binary search. Techniques: Corner cases:
- Sort intervals by start point. - No intervals, one or two intervals. Geometry
Things to look out for during interviews: - Check for overlapping intervals. - Non-overlapping intervals. Geometry studies properties of space related to distance, shape, size,
- Know the complexity of your language’s default sort (usually O(n log - Merge intervals. - An interval within another. and relative position. Most Computer Science courses focus on 2D
n)) (Timsort in Python) - Duplicate intervals. geometry, as advanced (e.g., 3D) geometry is less common. In algorithm
- Intervals starting where another interviews, geometry typically plays a minor role
arr . sort () # Ascending order ends: [[1, 2], [2, 3]].
arr . sort ( reverse = True ) # Descending order
arr . sort ( key = lambda x : x [0]) # Based on the key Techniques: Corner cases:
function . def is_overlap (a , b ) : - Distance between two points - Zero values. This always gets
return a [0] < b [1] and b [0] < a [1] - Overlapping circles people
Techniques: Corner cases: - Overlapping rectangles
def merge_overlapping_intervals (a , b ) :
- Sorted inputs - Empty sequence
return [ min ( a [0] , b [0]) , max ( a [1] , b [1]) ]
- Sorting an input that has limited - Sequence with 1-2 element Helpful Resources:
range - Sequence containing duplicates Tech Interview Handbook
Helpful Resources:
Helpful Resources: Tech Interview Handbook
Tech Interview Handbook
Zero To Mastery
Piero24 ¯ pietrobonandrea [Link]
SuperHero Valley Cracking The Coding Interview: Condition (n) Complexity and
Sunil Notebook US - UK - DE - IT - FR - ES - JP Techniques
Tech Interview Handbook Elements Of Programming Interviews: n < 20 2n , n!
Try Exponent US - UK - DE - IT - FR - ES - JP e.g. brute force,
LeetCode Competitive Programmer’s HandBook: - backtracking
interviewBit DataStructures and Algoritms in Python: -
n < 3000 n2
1point3acres Grokking Algorithms:
e.g. dynamic
CodeForces US - UK - DE - IT - FR - ES - JP
programming
HelloInterview Grokking Data Structures:
3000 < n < 106 O(n), O(n log n)
US - UK - DE - IT - FR - ES - JP
e.g. 2 pointers, greedy,
The Software Engineer’s Guidebook:
heap, sorting
Usefull Links - DSA US - UK - DE - IT - FR - ES - JP
n > 106 O(log n), O(1)
Interview Cake Building a Career in Software:
e.g. binary search, math
Zero To Mastery US - UK - DE - IT - FR - ES - JP
Python Cheat Sheet System Design Interview: Sites to find companies to apply to: LinkedIn, Glassdoor, [Link]
Algo Monster US - UK - DE - IT - FR - ES - JP
LeetCode ALL
CodeInMotion
VisuAlgo Steps for a good Technical Interview
NeetCode - 150
8. Explain your thought process while coding.