| Algorithm | Best | Worst |
|---|---|---|
| Binary Search | O(1) | O(log n) |
| Merge Sort | O(n log n) | O(n log n) |
| Quick Sort | O(n log n) | O(nΒ²) |
| BFS / DFS | O(V+E) | O(V+E) |
| Dijkstra | O((V+E) log V) | O((V+E) log V) |
| Hash Lookup | O(1) | O(n) |
Data Structures & Algorithms
Interview Questions & Answers
π±Beginner QuestionsQ1βQ14
Big O notation describes how an algorithm's runtime or memory usage grows as the input size n grows. It expresses the worst-case upper bound, ignoring constants and lower-order terms.
An array is a contiguous block of memory storing elements of the same type, accessed by index in O(1) time. It is the most fundamental data structure.
| Operation | Array | Dynamic Array (ArrayList) |
|---|---|---|
| Access by index | O(1) | O(1) |
| Search (unsorted) | O(n) | O(n) |
| Search (sorted) | O(log n) | O(log n) |
| Insert at end | O(1)* | O(1) amortized |
| Insert at middle | O(n) | O(n) |
| Delete at middle | O(n) | O(n) |
| Operation | Array | Linked List |
|---|---|---|
| Access by index | O(1) β | O(n) β |
| Insert at head | O(n) | O(1) β |
| Insert at tail | O(1)* | O(1) with tail ptr β |
| Insert at middle | O(n) | O(n) (search) + O(1) (insert) |
| Memory | Contiguous, cache-friendly | Scattered, pointer overhead |
| Feature | Stack | Queue |
|---|---|---|
| Order | LIFO (Last In, First Out) | FIFO (First In, First Out) |
| Operations | push, pop, peek | enqueue, dequeue, front |
| All ops time | O(1) | O(1) |
| Use cases | Undo/redo, call stack, DFS, balanced brackets | BFS, task scheduling, print queue, rate limiting |
| Variants | Min-stack, monotonic stack | Deque, priority queue, circular queue |
A hash map (hash table, dictionary) stores key-value pairs. A hash function converts the key into an array index, enabling O(1) average-case access. Collisions (two keys map to same index) are resolved by chaining or open addressing.
Collision handling: Chaining β each bucket is a linked list of entries. Open addressing β on collision, probe next empty slot (linear, quadratic, double hashing). Load factor (entries/capacity) determines when to resize (rehash) β typically at 0.75.
Binary search finds a target in a sorted array in O(log n) by repeatedly halving the search space. Each step eliminates half the remaining candidates.
A BST is a binary tree with the property: for every node, all values in the left subtree are less and all values in the right subtree are greater. This enables O(log n) search, insert, and delete on a balanced BST.
Worst case: A degenerate BST (sorted insert) becomes a linked list β O(n) operations. Self-balancing BSTs (AVL, Red-Black Tree) guarantee O(log n) height.
Recursion is when a function calls itself to solve a smaller version of the same problem. Every recursive function needs a base case (stopping condition) to prevent infinite recursion.
| Algorithm | Best | Average | Worst | Space | Stable? |
|---|---|---|---|---|---|
| Bubble Sort | O(n) | O(nΒ²) | O(nΒ²) | O(1) | β |
| Selection Sort | O(nΒ²) | O(nΒ²) | O(nΒ²) | O(1) | β |
| Insertion Sort | O(n) | O(nΒ²) | O(nΒ²) | O(1) | β |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | β |
| Quick Sort | O(n log n) | O(n log n) | O(nΒ²) | O(log n) | β |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | β |
| Counting Sort | O(n+k) | O(n+k) | O(n+k) | O(k) | β |
A heap is a complete binary tree stored as an array where the parent is always greater than (max-heap) or less than (min-heap) its children. It supports fast access to the max/min element.
| Operation | Time |
|---|---|
| Get min/max (peek) | O(1) |
| Insert (push) | O(log n) β bubble up |
| Remove min/max (pop) | O(log n) β bubble down |
| Build heap from array | O(n) |
| Heap sort | O(n log n) |
A graph is a set of vertices (nodes) connected by edges. Graphs can be directed or undirected, weighted or unweighted, cyclic or acyclic.
| Feature | Adjacency List | Adjacency Matrix |
|---|---|---|
| Space | O(V + E) β sparse-friendly | O(VΒ²) β always |
| Check edge (u,v) | O(degree of u) | O(1) |
| Get all neighbors | O(degree) | O(V) |
| Best for | Sparse graphs (most real graphs) | Dense graphs, fast edge lookup |
| Feature | BFS (Breadth-First) | DFS (Depth-First) |
|---|---|---|
| Data structure | Queue | Stack (or recursion) |
| Traversal order | Level by level (wide) | Go deep before backtracking |
| Shortest path? | β Guarantees shortest (unweighted) | β Not guaranteed |
| Memory | O(w) width of graph | O(h) height of graph |
| Best for | Shortest path, nearest node, level-order | Cycle detection, topological sort, maze solving |
A trie is a tree where each node represents a character, and paths from root to terminal nodes represent words. Extremely efficient for prefix-based operations.
Use cases: Autocomplete, spell-checkers, IP routing (longest prefix match), word game dictionaries, prefix-based rate limiting.
β‘Intermediate QuestionsQ15βQ28
Dynamic programming (DP) solves problems by breaking them into overlapping subproblems, solving each once, and storing results to avoid redundant computation. It applies when a problem has optimal substructure and overlapping subproblems.
| Approach | Top-Down (Memoization) | Bottom-Up (Tabulation) |
|---|---|---|
| Direction | Start at problem, recurse down | Start at base case, build up |
| Implementation | Recursion + cache (memo) | Iterative loops + DP table |
| Space | Call stack + memo O(n) | DP array O(n) or O(1) optimised |
| Easier to write? | β Follows natural recursion | Requires understanding DP order |
Given items with weights and values, and a knapsack of capacity W, find the maximum value you can fit. Each item can be included at most once (0 or 1).
w from W down to weight[i]. This makes it O(W) space. The classic pattern for knapsack-style problems.LCS finds the longest subsequence present in both strings (characters don't need to be contiguous). Classic DP problem that underlies git diff, DNA alignment, and plagiarism detection.
Dijkstra's algorithm finds the shortest path from a source vertex to all other vertices in a weighted graph with non-negative edge weights. Uses a min-heap (priority queue) to always process the nearest unvisited vertex next.
Union-Find efficiently tracks which elements belong to the same group (connected component). Supports two operations: find (which group?) and union (merge two groups). Used for detecting cycles, Kruskal's MST, network connectivity.
Topological sort produces a linear ordering of vertices in a Directed Acyclic Graph (DAG) such that for every edge uβv, u comes before v. Used for task scheduling, build order, course prerequisites.
The two-pointer technique uses two indices (pointers) that move toward each other or in the same direction. It converts O(nΒ²) brute-force solutions to O(n) for many array/string problems.
The sliding window technique maintains a contiguous subarray/substring of a certain property, expanding or shrinking from one end to avoid reprocessing elements. Converts O(nΒ²) or O(nΒ³) solutions to O(n).
Backtracking builds a solution incrementally, pruning branches as soon as it determines they cannot lead to a valid solution. It's smarter than brute force because it abandons partial candidates early.
Classic backtracking problems: N-Queens, Sudoku solver, word search in grid, generate all subsets/combinations/permutations, letter combinations of phone number.
A monotonic stack maintains elements in increasing or decreasing order. When a new element violates the order, elements are popped β and at the moment of popping, you know the "next greater/smaller element" relationship.
A segment tree is a binary tree that enables efficient range queries (sum, min, max) and point updates on an array in O(log n) β compared to O(n) for naive approaches.
Kadane's algorithm finds the maximum sum contiguous subarray in O(n) time and O(1) space. It's a classic DP problem where at each position you decide: extend the previous subarray or start fresh.
Greedy algorithms make the locally optimal choice at each step, hoping to reach a globally optimal solution. They work when a problem has the greedy choice property (local optimum leads to global optimum) and optimal substructure.
The fast/slow pointer (Floyd's cycle detection) technique uses two pointers moving at different speeds. Used for cycle detection, finding middle elements, and more.
π₯Advanced QuestionsQ29βQ40
| Pattern | Recurrence | Examples |
|---|---|---|
| Linear DP | dp[i] = f(dp[i-1], dp[i-2]) | Fibonacci, climbing stairs, coin change |
| 2D DP | dp[i][j] = f(dp[i-1][j], dp[i][j-1]) | LCS, edit distance, unique paths |
| Interval DP | dp[i][j] = f(dp[i][k], dp[k+1][j]) | Matrix chain multiply, burst balloons |
| Knapsack | dp[i][w] = max(skip, take) | 0/1 knapsack, partition equal subset |
| Tree DP | dp[node] = f(dp[children]) | House robber III, diameter of tree |
| Bitmask DP | dp[mask] = f(dp[mask ^ bit]) | TSP, assignment problem |
QuickSort picks a pivot, partitions the array (elements < pivot left, > pivot right), then recursively sorts each half. Average O(n log n), worst O(nΒ²) when pivot is always min/max.
An MST of a connected, weighted, undirected graph spans all vertices with minimum total edge weight, using exactly V-1 edges and no cycles. Used in network design, clustering, and approximation algorithms.
A balanced BST maintains O(log n) height by rebalancing after insertions and deletions. This guarantees O(log n) worst-case for all operations β unlike a regular BST which can degrade to O(n).
- AVL Tree: Every node's left and right subtree heights differ by at most 1 (balance factor β {-1, 0, 1}). Rebalances via rotations after each insert/delete. Stricter balance β faster lookup but more rotations than Red-Black.
- Red-Black Tree: Each node is red or black. Rules ensure path from root to leaf is at most 2Γ shortest path β height β€ 2 log n. Used in Java TreeMap, C++ std::map, Linux kernel scheduler. Fewer rotations than AVL β faster inserts/deletes.
- Rotations: Left rotation (LL case), Right rotation (RR case), Left-Right (LR case), Right-Left (RL case). Rotations are O(1) and restore balance.
- B-Tree / B+Tree: Used in databases and file systems. Nodes can have many children (high branching factor reduces height). B+Tree stores all data in leaves with linked list β enables efficient range queries.
Bellman-Ford finds shortest paths from a source to all vertices in a weighted graph β including graphs with negative edge weights. It also detects negative cycles. Slower than Dijkstra but more general.
Place N queens on an NΓN board so no two queens attack each other (same row, column, or diagonal). Classic backtracking problem.
Standard BFS explores all nodes up to distance d from the source. Bidirectional BFS runs BFS from both source AND destination simultaneously, meeting in the middle β dramatically reducing nodes explored.
- Standard BFS: Explores O(b^d) nodes where b = branching factor, d = distance.
- Bidirectional BFS: Each direction explores O(b^(d/2)) nodes β total O(2 Γ b^(d/2)) = exponentially fewer nodes.
- Example: b=10, d=6. Standard: 10βΆ = 1,000,000 nodes. Bidirectional: 2 Γ 10Β³ = 2,000 nodes. 500Γ faster!
Suffix arrays and suffix trees are data structures for efficient string operations, used in text search engines, bioinformatics (DNA sequencing), and data compression.
- Suffix Array: Sorted array of all suffix starting positions. O(n log n) construction. Uses O(n) space. Pattern matching in O(m log n) with binary search.
- Suffix Tree: Compressed trie of all suffixes. O(n) construction (Ukkonen's algorithm). O(m) pattern matching. Enables many O(n) string algorithms (LCS of two strings, longest repeated substring).
- LCP Array: Longest Common Prefix between adjacent suffixes in sorted order. Combined with suffix array enables efficient repeated substring queries.
Knuth-Morris-Pratt (KMP) finds all occurrences of a pattern in a text in O(n + m) β faster than naive O(nm) because it avoids re-examining characters by using a failure function (partial match table).
A Fenwick Tree (BIT) supports prefix sum queries and point updates in O(log n) time with O(n) space β simpler to implement than a segment tree for this specific use case.
Recognising patterns is what separates strong candidates. Map problem characteristics to the right technique:
| If the problem involves... | Think about... |
|---|---|
| Top/bottom K elements | Heap (priority queue) |
| Sorted array, find pair/triplet | Two pointers |
| Subarray/substring with constraint | Sliding window |
| Tree/graph traversal | BFS (level, shortest path) / DFS (path, cycle) |
| All possible combinations/subsets | Backtracking |
| Overlapping subproblems, optimisation | Dynamic programming |
| Sorted array, efficient search | Binary search |
| Connected components, cycle detection | Union-Find |
| Prefix/word lookup | Trie |
| Range queries + updates | Segment tree / Fenwick tree |
| Next greater/smaller element | Monotonic stack |
| Task ordering with dependencies | Topological sort |
| Shortest path, weighted graph | Dijkstra / Bellman-Ford |
| Interval scheduling / merging | Sort by start/end + greedy |
Last One: DevOps & Docker
DSA done. The final page in this series covers DevOps fundamentals β Docker, Kubernetes, CI/CD pipelines, monitoring, and cloud infrastructure.
β System Design Q&A