DSA Cheat Sheet: Quick Reference for Data Structures & Algorithms
Essential DSA cheat sheet covering arrays, trees, graphs, DP patterns, sorting, and searching — quick reference with complexity tables for interview day.
Arrays & Strings
Time Complexities
| Operation | Array | ArrayList | LinkedList |
|---|---|---|---|
| Access | O(1) | O(1) | O(n) |
| Search | O(n) | O(n) | O(n) |
| Insert (end) | O(1)* | O(1)* | O(1) |
| Insert (mid) | O(n) | O(n) | O(1) |
| Delete | O(n) | O(n) | O(1)* |
| Insert (beginning) | O(n) | O(n) | O(1) |
| Delete (beginning) | O(n) | O(n) | O(1) |
| Search (sorted) | O(log n) | O(log n) | O(n) |
| Reverse | O(n) | O(n) | O(n) |
| Sort | O(n log n) | O(n log n) | O(n log n) |
*Amortized O(1) for ArrayList/dynamic arrays due to occasional resizing.
Essential Patterns
Two Pointers (Sorted Array):
int left = 0, right = arr.length - 1;
while (left < right) {
int sum = arr[left] + arr[right];
if (sum == target) return new int[]{left, right};
else if (sum < target) left++;
else right--;
}
Sliding Window (Fixed Size):
int windowSum = 0, maxSum = 0;
for (int i = 0; i < n; i++) {
windowSum += arr[i];
if (i >= k) windowSum -= arr[i - k];
maxSum = Math.max(maxSum, windowSum);
}
Sliding Window (Variable Size):
int left = 0, windowSum = 0, maxLen = 0;
for (int right = 0; right < n; right++) {
windowSum += arr[right];
while (windowSum > target) {
windowSum -= arr[left];
left++;
}
maxLen = Math.max(maxLen, right - left + 1);
}
Fast & Slow Pointers (Cycle Detection):
int slow = 0, fast = 0;
do {
slow = arr[slow]; // move 1 step
fast = arr[arr[fast]]; // move 2 steps
} while (slow != fast);
// Cycle exists; find entry point
slow = 0;
while (slow != fast) {
slow = arr[slow];
fast = arr[fast];
}
return slow; // cycle entry
Prefix Sum:
int[] prefix = new int[n + 1];
for (int i = 0; i < n; i++) {
prefix[i + 1] = prefix[i] + arr[i];
}
// Range sum [l, r] = prefix[r+1] - prefix[l]
Hash Maps
Operations
| Operation | Average | Worst |
|---|---|---|
| Insert | O(1) | O(n) |
| Delete | O(1) | O(n) |
| Search | O(1) | O(n) |
| Size | O(1) | O(1) |
| Iteration | O(n) | O(n) |
| Merge (Union) | O(n) | O(n) |
Pattern: Two Sum
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[]{map.get(complement), i};
}
map.put(nums[i], i);
}
Pattern: Frequency Count
Map<Integer, Integer> freq = new HashMap<>();
for (int num : nums) {
freq.merge(num, 1, Integer::sum);
}
// Find elements appearing more than n/2 times
for (Map.Entry<Integer, Integer> e : freq.entrySet()) {
if (e.getValue() > nums.length / 2) return e.getKey();
}
Trees
Traversals
// Inorder: Left -> Root -> Right (sorted for BST)
void inorder(TreeNode node) {
if (node == null) return;
inorder(node.left);
System.out.println(node.val);
inorder(node.right);
}
// Preorder: Root -> Left -> Right (clone tree)
// Postorder: Left -> Right -> Root (delete tree)
// Level Order: BFS with Queue (level-by-level)
BST Operations
| Operation | Average | Worst |
|---|---|---|
| Search | O(log n) | O(n) |
| Insert | O(log n) | O(n) |
| Delete | O(log n) | O(n) |
| Min/Max | O(log n) | O(n) |
| Successor | O(log n) | O(n) |
| Predecessor | O(log n) | O(n) |
| Validate BST | O(n) | O(n) |
| LCA | O(log n) | O(n) |
Tree Height & Depth
// Max depth (recursive)
int maxDepth(TreeNode root) {
if (root == null) return 0;
return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}
// Min depth (BFS stops at first leaf)
int minDepth(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
int depth = 1;
while (!q.isEmpty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
TreeNode node = q.poll();
if (node.left == null && node.right == null) return depth;
if (node.left != null) q.offer(node.left);
if (node.right != null) q.offer(node.right);
}
depth++;
}
return depth;
}
Graphs
BFS Template
void bfs(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
// process node
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
}
DFS Template
void dfs(TreeNode node) {
if (node == null) return;
// process node
dfs(node.left);
dfs(node.right);
}
Graph BFS (Adjacency List)
void bfs(List<List<Integer>> adj, int start) {
boolean[] visited = new boolean[adj.size()];
Queue<Integer> queue = new LinkedList<>();
visited[start] = true;
queue.offer(start);
while (!queue.isEmpty()) {
int node = queue.poll();
for (int neighbor : adj.get(node)) {
if (!visited[neighbor]) {
visited[neighbor] = true;
queue.offer(neighbor);
}
}
}
}
Topological Sort (Kahn's Algorithm)
List<Integer> topologicalSort(List<List<Integer>> adj, int n) {
int[] inDegree = new int[n];
for (int i = 0; i < n; i++)
for (int j : adj.get(i)) inDegree[j]++;
Queue<Integer> queue = new LinkedList<>();
for (int i = 0; i < n; i++)
if (inDegree[i] == 0) queue.offer(i);
List<Integer> result = new ArrayList<>();
while (!queue.isEmpty()) {
int node = queue.poll();
result.add(node);
for (int neighbor : adj.get(node)) {
inDegree[neighbor]--;
if (inDegree[neighbor] == 0) queue.offer(neighbor);
}
}
return result.size() == n ? result : new ArrayList<>(); // empty if cycle
}
Union-Find (Disjoint Set)
class UnionFind {
int[] parent, rank;
UnionFind(int n) {
parent = new int[n]; rank = new int[n];
for (int i = 0; i < n; i++) parent[i] = i;
}
int find(int x) {
if (parent[x] != x) parent[x] = find(parent[x]); // path compression
return parent[x];
}
void union(int x, int y) {
int px = find(x), py = find(y);
if (px == py) return;
if (rank[px] < rank[py]) parent[px] = py;
else if (rank[px] > rank[py]) parent[py] = px;
else { parent[py] = px; rank[px]++; }
}
}
Graph Complexity Summary
| Algorithm | Time | Space | Use Case |
|---|---|---|---|
| BFS | O(V + E) | O(V) | Shortest path (unweighted), level traversal |
| DFS | O(V + E) | O(V) | Cycle detection, connected components |
| Dijkstra | O((V + E) log V) | O(V) | Shortest path (weighted, non-negative) |
| Bellman-Ford | O(V * E) | O(V) | Shortest path (negative weights) |
| Floyd-Warshall | O(V^3) | O(V^2) | All-pairs shortest path |
| Topological Sort | O(V + E) | O(V) | Task scheduling, dependency resolution |
| Union-Find | O(α(n)) amortized | O(V) | Dynamic connectivity, cycle detection |
Sorting Algorithms
| Algorithm | Time (Best) | Time (Avg) | Time (Worst) | Space | Stable |
|---|---|---|---|---|---|
| Bubble | O(n) | O(n^2) | O(n^2) | O(1) | Yes |
| Selection | O(n^2) | O(n^2) | O(n^2) | O(1) | No |
| Insertion | O(n) | O(n^2) | O(n^2) | O(1) | Yes |
| Merge | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes |
| Quick | O(n log n) | O(n log n) | O(n^2) | O(log n) | No |
| Heap | O(n log n) | O(n log n) | O(n log n) | O(1) | No |
| Counting | O(n + k) | O(n + k) | O(n + k) | O(k) | Yes |
| Radix | O(d * n) | O(d * n) | O(d * n) | O(n + k) | Yes |
| Bucket | O(n + k) | O(n + k) | O(n^2) | O(n) | Yes |
When to Use Which
- Quick Sort: Default choice, fastest in practice, cache-friendly.
- Merge Sort: When stable sort is needed or data is linked/external.
- Heap Sort: When O(1) space and O(n log n) guarantee is needed.
- Counting Sort: When range of values k is small relative to n.
- Radix Sort: When sorting integers with known digit count.
- Insertion Sort: When n is very small (< 20) or data is nearly sorted.
- Tim Sort (Java's Arrays.sort for objects): Hybrid of merge and insertion, stable.
Dynamic Programming
Memoization Template (Top-Down)
Map<Integer, Integer> memo = new HashMap<>();
int solve(int n) {
if (n == 0) return baseCase;
if (memo.containsKey(n)) return memo.get(n);
int result = // recurrence using solve(n-1), solve(n-2), etc.
memo.put(n, result);
return result;
}
Tabulation Template (Bottom-Up)
int[] dp = new int[n + 1];
dp[0] = baseCase;
for (int i = 1; i <= n; i++) {
dp[i] = // recurrence using dp[i-1], dp[i-2], etc.
}
return dp[n];
2D DP Template
int[][] dp = new int[m + 1][n + 1];
dp[0][0] = baseCase;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
dp[i][j] = // recurrence using dp[i-1][j], dp[i][j-1], dp[i-1][j-1]
}
}
return dp[m][n];
Classic Problems
| Problem | Recurrence | Pattern |
|---|---|---|
| Fibonacci | dp[i] = dp[i-1] + dp[i-2] | 1D linear |
| Climbing Stairs | dp[i] = dp[i-1] + dp[i-2] | 1D linear |
| Coin Change | dp[i] = min(dp[i-coin] + 1) | 1D unbounded |
| 0/1 Knapsack | dp[i][w] = max(include, exclude) | 2D |
| Longest Common Subseq | dp[i][j] = max(dp[i-1][j], dp[i][j-1]) | 2D |
| Edit Distance | dp[i][j] = min(insert, delete, replace) | 2D |
| Longest Increasing Subseq | dp[i] = max(dp[j] + 1) for j < i | 1D O(n^2) |
| Maximum Subarray Sum | dp[i] = max(arr[i], dp[i-1] + arr[i]) | Kadane's |
| House Robber | dp[i] = max(dp[i-2] + arr[i], dp[i-1]) | 1D linear |
| Word Break | dp[i] = dp[j] && dict.contains(s[j:i]) | 1D |
| Burst Balloons | dp[i][j] = max(dp[i][k] + dp[k+1][j] + ...) | Interval DP |
| Longest Palindromic Subseq | dp[i][j] = dp[i+1][j-1] + 2 if match | Interval DP |
| Unique Paths | dp[i][j] = dp[i-1][j] + dp[i][j-1] | 2D grid |
| Minimum Path Sum | dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] | 2D grid |
DP Pattern Recognition Guide
- Linear DP: Problem depends on previous 1-2 states (Fibonacci, climbing stairs, house robber).
- 2D Grid DP: Navigate grid, choose paths (unique paths, min path sum).
- Knapsack variants: 0/1 (each item once), unbounded (repeat), multiple (limited copies).
- Interval DP: Optimal way to merge/parenthesize (matrix chain, burst balloons).
- String DP: Subsequence/substring problems (LCS, edit distance, palindrome).
- Bitmask DP: Small n (<= 20), subset enumeration (TSP, assignment).
Binary Search
Standard Template
int binarySearch(int[] arr, int target) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
Leftmost (First Occurrence)
int leftBound(int[] arr, int target) {
int left = 0, right = arr.length - 1, result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] >= target) {
if (arr[mid] == target) result = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return result;
}
Rightmost (Last Occurrence)
int rightBound(int[] arr, int target) {
int left = 0, right = arr.length - 1, result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] <= target) {
if (arr[mid] == target) result = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
Search in Rotated Sorted Array
int searchRotated(int[] arr, int target) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
if (arr[left] <= arr[mid]) { // left half sorted
if (target >= arr[left] && target < arr[mid]) right = mid - 1;
else left = mid + 1;
} else { // right half sorted
if (target > arr[mid] && target <= arr[right]) left = mid + 1;
else right = mid - 1;
}
}
return -1;
}
Binary Search on Answer
// Find minimum value that satisfies condition
int lo = minVal, hi = maxVal;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (isSatisfied(mid)) hi = mid;
else lo = mid + 1;
}
return lo;
Binary Search Complexity Summary
| Variant | Time | Space | Notes |
|---|---|---|---|
| Standard | O(log n) | O(1) | Exact match |
| Left/Right bound | O(log n) | O(1) | First/last occurrence |
| Rotated array | O(log n) | O(1) | Pivot detection |
| 2D matrix | O(log(m*n)) | O(1) | Row-col sorted |
| Answer binary search | O(log(range) * check) | O(1) | Monotonic predicate |
Quick Reference
Data Structure Comparison
| Data Structure | Access | Search | Insert | Delete | Use Case |
|---|---|---|---|---|---|
| Array | O(1) | O(n) | O(n) | O(n) | Fast access, fixed size |
| ArrayList | O(1) | O(n) | O(1)* | O(n) | Dynamic array, fast access |
| LinkedList | O(n) | O(n) | O(1) | O(1) | Frequent insert/delete |
| Stack | O(n) | O(n) | O(1) | O(1) | LIFO, undo, DFS |
| Queue | O(n) | O(n) | O(1) | O(1) | FIFO, BFS |
| Deque | O(1) | O(n) | O(1) | O(1) | Both ends, sliding window |
| HashMap | N/A | O(1) | O(1) | O(1) | Key-value lookups |
| TreeMap | N/A | O(log n) | O(log n) | O(log n) | Sorted keys, range queries |
| HashSet | N/A | O(1) | O(1) | O(1) | Unique elements, membership |
| Heap | N/A | O(n) | O(log n) | O(log n) | Priority queue, min/max |
| BST | O(log n) | O(log n) | O(log n) | O(log n) | Sorted data, range queries |
| Trie | O(L) | O(L) | O(L) | O(L) | Prefix search, autocomplete |
| Graph (adj list) | - | O(V+E) | O(1) | O(E) | Sparse graphs, traversal |
| Graph (adj matrix) | - | O(1) | O(1) | O(1) | Dense graphs, quick lookup |
Stack & Queue Templates
// Monotonic Stack (Next Greater Element)
int[] nextGreater(int[] arr) {
int[] result = new int[arr.length];
Stack<Integer> stack = new Stack<>();
for (int i = arr.length - 1; i >= 0; i--) {
while (!stack.isEmpty() && stack.peek() <= arr[i]) stack.pop();
result[i] = stack.isEmpty() ? -1 : stack.peek();
stack.push(arr[i]);
}
return result;
}
// LRU Cache using LinkedHashMap
LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>(capacity, 0.75f, true) {
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > capacity;
}
};
Heap / Priority Queue
// Min-heap
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
// Max-heap
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
// Custom comparator
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]);
String Operations
| Operation | Time | Notes |
|---|---|---|
| Concatenation | O(n) | Use StringBuilder |
| Substring | O(n) | Java creates new string |
| Search (naive) | O(n*m) | Brute force |
| Search (KMP) | O(n+m) | Pattern matching |
| Reverse | O(n) | Two pointers |
| Palindrome check | O(n) | Two pointers from center |
| Anagram check | O(n) | Frequency count or sort |
Common Interview Shortcuts
| Pattern | When to Use | Time |
|---|---|---|
| Two Sum (HashMap) | Find pair with sum | O(n) |
| Sliding Window | Subarray/substring problems | O(n) |
| Fast & Slow Pointers | Cycle detection, middle of list | O(n) |
| Merge Intervals | Overlapping intervals | O(n log n) |
| Top K Elements | K largest/smallest | O(n log k) |
| Binary Search | Sorted/search space | O(log n) |
| BFS (Queue) | Shortest path, level order | O(V+E) |
| DFS (Stack/Recursion) | Path finding, connected components | O(V+E) |
| Union-Find | Dynamic connectivity | O(α(n)) |
| Trie | Prefix matching, autocomplete | O(L) |
| Monotonic Stack | Next greater/smaller element | O(n) |
| Kadane's Algorithm | Maximum subarray sum | O(n) |
| Topological Sort | Task ordering with dependencies | O(V+E) |
| Bit Manipulation | Subset enumeration, XOR tricks | O(1) per op |
Resources
- DSA Roadmap - Complete learning path
- Practice Problems - Practice problems
- Topic Deep Dives - Detailed explanations
- Coding Patterns - 15 essential patterns
- DSA Guide - Full reference
Related Articles
Data Structures and Algorithms Guide: Complete Reference
Complete data structures and algorithms guide with visual diagrams, runnable code, complexity tables, and interview-focused explanations of every core topic.
System DesignSystem Design Interview Guide 2026: Complete Preparation Framework
Master system design interviews with our complete guide. Learn the framework, common topics, real-world case studies, and practice questions with model answers.
Interview PrepBehavioral Interview Questions 2026: STAR Method Guide
Nail behavioral interviews with proven STAR method examples. Learn to answer leadership, conflict, and failure questions.
Continue Your Prep
Apply what you learned with our structured roadmaps and practice problems.