Chapter 13 — LeetCode & Algorithms Interview Questions
This chapter is designed for Senior Software Engineer interviews.
For each problem, focus on:
- Understanding the pattern
- Explaining your approach
- Complexity analysis
- Writing clean code
Most companies do not expect only a working solution. They evaluate:
- problem solving
- communication
- trade-off decisions
- code quality
Examples use Python, because it is concise for algorithm interviews.
1. What is Big-O notation?
Interview Answer
Big-O notation describes how the runtime or memory usage of an algorithm grows as the input size increases.
It helps compare algorithm efficiency.
Common Complexities
O(1) — Constant Time
Execution time does not depend on input size.
Example:
value = array[0]
Whether the array has:
10 items
or:
10 million items
the operation takes the same time.
O(n) — Linear Time
Runtime grows proportionally with input size.
Example:
for item in array:
print(item)
Array:
10 items → 10 operations
1000 items → 1000 operations
O(log n) — Logarithmic Time
Input is reduced by half each step.
Example:
Binary search.
1000 items
500
250
125
...
O(n²) — Quadratic Time
Usually nested loops.
Example:
for i in array:
for j in array:
print(i,j)
Complexity Table
Complexity | Example |
O(1) | Hash lookup |
O(log n) | Binary search |
O(n) | Loop |
O(n log n) | Merge sort |
O(n²) | Nested loops |
Senior Answer
Big-O describes how an algorithm scales as input grows. I use it to evaluate performance trade-offs between different solutions.
2. How do you analyze an algorithm?
Interview Answer
I analyze:
- Time complexity
- Space complexity
- Input constraints
- Possible optimizations
Example:
Find maximum number:
def find_max(nums):
max_value = nums[0]
for n in nums:
if n > max_value:
max_value = n
return max_value
Time:
Loop runs:
n times
Therefore:
O(n)
Space:
Only one variable:
max_value
Therefore:
O(1)
Senior Answer
I first understand the constraints, then choose an appropriate data structure and evaluate both runtime and memory complexity.
3. How do you solve the Two Sum problem?
Problem
Given:
nums = [2,7,11,15]
target = 9
Return indexes of two numbers:
2 + 7 = 9
Output:
[0,1]
Brute Force Solution
Check every pair:
def two_sum(nums, target):
for i in range(len(nums)):
for j in range(i+1,len(nums)):
if nums[i] + nums[j] == target:
return [i,j]
Complexity:
Time:
O(n²)
Space:
O(1)
Optimized Solution Using Hash Map
Idea:
Store numbers we have already seen.
For each number:
needed = target - current
If needed exists:
we found the answer.
Code:
def two_sum(nums, target):
seen = {}
for i, value in enumerate(nums):
complement = target - value
if complement in seen:
return [seen[complement], i]
seen[value] = i
Example:
nums=[2,7,11,15]
target=9
Step 1:
value=2
needed=7
store:
{
2:0
}
Step 2:
value=7
needed=2
2 exists
return [0,1]
Complexity:
Time:
O(n)
Space:
O(n)
Senior Answer
I use a hash map to store previously visited numbers. This reduces the solution from quadratic time to linear time.
4. What is the difference between Array and Hash Table?
Interview Answer
They solve different problems.
Array
Stores elements sequentially.
Example:
numbers = [10,20,30]
Access:
numbers[1]
Complexity:
O(1)
Search:
O(n)
because we may scan every element.
Hash Table
Stores key-value pairs.
Example:
user = {
"id":101,
"name":"John"
}
Lookup:
user["id"]
Average:
O(1)
Comparison
Array | Hash Table | |
Access by index | Excellent | No |
Lookup by key | Poor | Excellent |
Order | Yes | Depends |
Memory | Less | More |
Senior Answer
Arrays provide fast indexed access, while hash tables provide fast lookup by key. I choose based on the access pattern required.
5. How does a Hash Table work internally?
Interview Answer
A hash table uses a hash function to convert a key into an array index.
Example:
Key:
"John"
Hash function:
hash("John")
Result:
index 5
Store:
Bucket[5] = John
Architecture:
Key
|
Hash Function
|
Array Index
|
Bucket
Collision Problem
Two keys can generate the same index.
Example:
John → index 5
Mike → index 5
Solutions:
- chaining
- open addressing
Python Dictionary
Python:
dictionary = {}
is implemented using a hash table.
Senior Answer
Hash tables use hashing to map keys to storage locations, providing average O(1) insertion and lookup. Collisions are handled using techniques such as chaining.
6. What is the difference between Stack and Queue?
Interview Answer
Both are linear data structures but follow different access rules.
Stack
LIFO:
Last In, First Out.
Example:
Stack of plates.
Top
Plate 3
Plate 2
Plate 1
Operations:
Push:
add item
Pop:
remove last item
Python:
stack=[]
stack.append(10)
stack.pop()
Uses:
- function calls
- undo operations
- expression parsing
Queue
FIFO:
First In, First Out.
Example:
People waiting in line.
First → Second → Third
Python:
from collections import deque
queue = deque()
queue.append(10)
queue.popleft()
Uses:
- message queues
- task processing
- BFS algorithms
Senior Answer
A stack uses LIFO ordering and is useful for nested operations, while a queue uses FIFO ordering and is used for scheduling and breadth-first processing.
7. Solve Valid Parentheses
Problem
Given:
"()[]{}"
Return:
True
Invalid:
"(]"
Return:
False
Approach
Use a stack.
Opening brackets:
push
Closing brackets:
compare with top
Code:
def is_valid(s):
stack = []
pairs = {
')':'(',
']':'[',
'}':'{'
}
for char in s:
if char in pairs:
if not stack or stack[-1] != pairs[char]:
return False
stack.pop()
else:
stack.append(char)
return len(stack)==0
Example:
Input:
{[]}
Process:
{
stack=[{]
[
stack=[{,[ ]
]
remove [
}
remove {
Valid.
Complexity:
Time:
O(n)
Space:
O(n)
Senior Answer
This problem follows the stack pattern because brackets must be closed in reverse order of opening.
8. What is the Two Pointer technique?
Interview Answer
Two pointers use two indexes to efficiently process arrays, usually reducing nested loops.
Example:
Sorted array:
[1,2,3,4,6]
Find pair:
sum=7
Use:
left
right
L R
1 2 3 4 6
If:
1+6 > 7
move right.
If:
1+6 ==7
found.
Code:
def two_sum_sorted(nums,target):
left=0
right=len(nums)-1
while left < right:
total=nums[left]+nums[right]
if total==target:
return [left,right]
elif total < target:
left+=1
else:
right-=1
Complexity:
Time:
O(n)
Space:
O(1)
Common Problems
Two pointers appear in:
- Two Sum II
- Remove duplicates
- Container With Most Water
- Valid palindrome
9. What is the Sliding Window technique?
Interview Answer
Sliding window maintains a moving range of elements to avoid repeated calculations.
Example:
Find maximum sum of 3 consecutive numbers.
Array:
[2,1,5,1,3,2]
Window:
[2,1,5]
Move:
[1,5,1]
Instead of recalculating:
O(n*k)
we update:
remove old value
add new value
Code:
def max_sum(nums,k):
window=sum(nums[:k])
result=window
for i in range(k,len(nums)):
window += nums[i]
window -= nums[i-k]
result=max(result,window)
return result
Complexity:
Time:
O(n)
Space:
O(1)
Common Problems
- Longest substring without repeating characters
- Maximum average subarray
- Minimum window substring
10. What is recursion?
Interview Answer
Recursion is when a function calls itself to solve smaller versions of the same problem.
Example:
Factorial:
5!
5 * 4 * 3 * 2 * 1
Recursive solution:
def factorial(n):
if n==1:
return 1
return n * factorial(n-1)
Execution:
factorial(5)
5 * factorial(4)
5 * 4 * factorial(3)
...
Every recursion needs:
Base Case
Stopping condition.
Example:
if n==1:
Recursive Case
Smaller problem.
Example:
factorial(n-1)
Complexity:
Time:
O(n)
Space:
O(n)
because of call stack.
Senior Answer
Recursion solves problems by breaking them into smaller subproblems. I always define a clear base case to avoid infinite recursion.
End of Chapter 13 — LeetCode & Algorithms
Covered:
✅ Big-O
✅ Complexity Analysis
✅ Two Sum
✅ Arrays vs Hash Tables
✅ Hash Table Internals
✅ Stack
✅ Queue
✅ Valid Parentheses
✅ Two Pointers
✅ Sliding Window
✅ Recursion
11. What is a Linked List?
Interview Answer
A linked list is a linear data structure where elements (nodes) are connected using references instead of being stored in continuous memory locations.
Array vs Linked List
Array
[10][20][30][40]
Memory:
1000 1004 1008 1012
Elements are stored together.
Linked List
+------+ +------+ +------+
| 10 | ---> | 20 | ---> | 30 |
+------+ +------+ +------+
Each node contains:
- data
- reference to next node
Node Structure
Python example:
class Node:
def __init__(self, value):
self.value = value
self.next = None
Advantages
Fast insertion/deletion
Adding a node:
Before:
10 → 20 → 30
Insert 15:
10 → 15 → 20 → 30
No shifting required.
Disadvantages
Slow access
To find item 30:
10 → 20 → 30
Need to traverse:
10
|
20
|
30
Complexity:
O(n)
Complexity
Operation | Array | Linked List |
Access | O(1) | O(n) |
Search | O(n) | O(n) |
Insert beginning | O(n) | O(1) |
Delete beginning | O(n) | O(1) |
Senior Answer
Linked lists provide efficient insertion and deletion because nodes are connected through references, but they sacrifice fast random access compared with arrays.
12. How do you reverse a Linked List?
Problem
Given:
1 → 2 → 3 → 4 → NULL
Return:
4 → 3 → 2 → 1 → NULL
Approach
Use three pointers:
- previous
- current
- next
Before:
prev current
NULL 1 → 2 → 3
Change direction:
prev ← current
Python Solution
def reverse_list(head):
previous = None
current = head
while current:
next_node = current.next
current.next = previous
previous = current
current = next_node
return previous
Complexity
Time:
O(n)
Space:
O(1)
Senior Answer
I reverse a linked list iteratively by changing each node's next reference while maintaining previous and current pointers. This provides O(n) time and O(1) memory.
13. How do you detect a cycle in a Linked List?
Problem
Example:
1 → 2 → 3 → 4
↑ |
|___|
The list contains a loop.
Solution: Fast and Slow Pointers
Also called:
Floyd's Cycle Detection Algorithm
Use:
Slow pointer:
moves 1 step
Fast pointer:
moves 2 steps
Example:
1 → 2 → 3 → 4 → 5
↑ |
|_____________|
Movement:
slow:
1 → 2 → 3
fast:
1 → 3 → 5 → 3
If they meet:
Cycle exists.
Python
def has_cycle(head):
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
Complexity
Time:
O(n)
Space:
O(1)
Senior Answer
Floyd's algorithm detects cycles using two pointers moving at different speeds. If a cycle exists, the fast pointer eventually catches the slow pointer.
14. What is Binary Search?
Interview Answer
Binary search finds an element in a sorted collection by repeatedly dividing the search space in half.
Example:
Array:
[1,3,5,7,9,11,13]
Find 9
Middle:
7
9 is greater:
Search right side:
[9,11,13]
Algorithm
- Find middle element
- Compare target
- Remove half of the search space
- Repeat
Python
def binary_search(nums, target):
left = 0
right = len(nums)-1
while left <= right:
middle = (left + right)//2
if nums[middle] == target:
return middle
elif nums[middle] < target:
left = middle + 1
else:
right = middle - 1
return -1
Complexity
Time:
O(log n)
Space:
O(1)
Requirements
Binary search requires:
- sorted data
- random access
Senior Answer
Binary search is efficient because each comparison eliminates half of the remaining search space. It requires sorted input.
15. What is Merge Sort?
Interview Answer
Merge sort is a divide-and-conquer sorting algorithm.
It divides the array into smaller parts, sorts them, and merges them back.
Example:
[8,3,5,1]
Split:
[8,3] [5,1]
Split:
[8][3][5][1]
Merge:
[3,8][1,5]
Final:
[1,3,5,8]
Algorithm
Divide
Split array in half.
Conquer
Sort each half.
Merge
Combine sorted halves.
Python
def merge_sort(nums):
if len(nums)<=1:
return nums
middle=len(nums)//2
left=merge_sort(nums[:middle])
right=merge_sort(nums[middle:])
return merge(left,right)
def merge(left,right):
result=[]
while left and right:
if left[0] < right[0]:
result.append(left.pop(0))
else:
result.append(right.pop(0))
return result + left + right
Complexity
Time:
O(n log n)
Space:
O(n)
Senior Answer
Merge sort provides predictable O(n log n) performance and is useful when stable sorting and predictable complexity are required.
16. What is a Binary Tree?
Interview Answer
A binary tree is a data structure where each node has at most two children:
- left child
- right child
Example:
10
/ \
5 20
/ \
3 7
Node
class TreeNode:
def __init__(self,value):
self.value=value
self.left=None
self.right=None
Terminology
Root:
10
Leaf:
3,7,20
Height:
Longest path from root to leaf.
Uses
- file systems
- databases
- search trees
- expression parsing
Senior Answer
A binary tree is a hierarchical structure where each node has up to two children. It is commonly used for searching, sorting, and representing hierarchical data.
17. Explain Binary Search Tree (BST).
Interview Answer
A Binary Search Tree is a binary tree with an ordering rule:
For every node:
Left subtree < Node < Right subtree
Example:
8
/ \
3 10
/ \ \
1 6 14
Searching:
Find 6.
Start:
8
6 is smaller:
go left.
3
6 is larger:
go right.
6 found
Complexity
Balanced tree:
Search:
O(log n)
Worst case:
O(n)
Example:
1
\
2
\
3
Senior Answer
A BST maintains ordering between nodes, allowing efficient search, insertion, and deletion when the tree is balanced.
18. What are Tree Traversals?
Interview Answer
Tree traversal means visiting every node in a tree.
The main types are:
- DFS
- BFS
Depth First Search (DFS)
Goes deep before moving sideways.
Three variations:
Preorder
Order:
Root → Left → Right
Example:
1
/ \
2 3
Output:
1 2 3
Inorder
Order:
Left → Root → Right
BST gives sorted output.
Output:
2 1 3
Postorder
Order:
Left → Right → Root
Output:
2 3 1
Python Example
def inorder(node):
if node:
inorder(node.left)
print(node.value)
inorder(node.right)
Senior Answer
Tree traversal algorithms allow processing hierarchical data. Inorder traversal of a BST is especially useful because it returns values in sorted order.
19. What is Breadth First Search (BFS)?
Interview Answer
BFS explores a tree or graph level by level using a queue.
Example:
1
/ \
2 3
/ \
4 5
Traversal:
1 → 2 → 3 → 4 → 5
Algorithm
Use queue:
from collections import deque
def bfs(root):
queue=deque([root])
while queue:
node=queue.popleft()
print(node.value)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
Complexity
Time:
O(n)
Space:
O(n)
Uses
- shortest path
- level order traversal
- social networks
Senior Answer
BFS processes nodes level by level using a queue. It is useful when we need the shortest path in an unweighted graph.
20. What is Depth First Search (DFS)?
Interview Answer
DFS explores as far as possible before backtracking.
It uses:
- recursion
- stack
Example:
A
/ \
B C
/
D
DFS:
A → B → D → C
Recursive Example
def dfs(node):
if not node:
return
print(node.value)
dfs(node.left)
dfs(node.right)
Complexity
Time:
O(n)
Space:
O(h)
where h is tree height.
DFS vs BFS
DFS | BFS |
Uses stack | Uses queue |
Goes deep | Goes wide |
Less memory usually | More memory |
Good for paths | Good for shortest path |
Senior Answer
DFS explores depth-first using recursion or a stack. It is useful for tree traversal, graph exploration, and backtracking problems.
End of Chapter 13 — LeetCode & Algorithms
Covered:
✅ Linked Lists
✅ Reverse Linked List
✅ Cycle Detection
✅ Binary Search
✅ Merge Sort
✅ Binary Trees
✅ Binary Search Trees
✅ Tree Traversals
✅ BFS
✅ DFS
21. What is a Graph?
Interview Answer
A graph is a data structure consisting of:
- vertices (nodes)
- edges (connections)
Graphs represent relationships between objects.
Example:
Social network:
Alice
/ \
Bob John
\
Mike
Nodes:
People
Edges:
Friend relationships
Graph Types
1. Directed Graph
Edges have direction.
Example:
Twitter follow:
A → B
A follows B.
2. Undirected Graph
Edges have no direction.
Example:
Friendship:
A ---- B
3. Weighted Graph
Edges have values.
Example:
Road network:
Toronto ----100km---- Ottawa
Graph Representation
1. Adjacency List
Most common.
Example:
graph = {
"A":["B","C"],
"B":["A"],
"C":["A"]
}
2. Adjacency Matrix
2D array:
A B C
A 0 1 1
B 1 0 0
C 1 0 0
Senior Answer
A graph models relationships between entities using nodes and edges. I usually use adjacency lists because they provide efficient storage and traversal for most real-world problems.
22. How do you traverse a Graph?
Interview Answer
The two main graph traversal algorithms are:
- BFS
- DFS
Example:
A
/ \
B C
/
D
DFS
Go deep first:
A → B → D → C
Uses:
- recursion
- stack
BFS
Go level by level:
A → B → C → D
Uses:
- queue
DFS Example
def dfs(graph, node, visited):
if node in visited:
return
visited.add(node)
print(node)
for neighbor in graph[node]:
dfs(graph, neighbor, visited)
Complexity
For graph:
Time:
O(V + E)
where:
- V = vertices
- E = edges
Space:
O(V)
Senior Answer
Graph traversal requires tracking visited nodes to avoid infinite loops. BFS is preferred for shortest paths, while DFS is useful for exploration and backtracking.
23. What is Topological Sort?
Interview Answer
Topological sorting orders nodes in a directed acyclic graph (DAG) so that dependencies come before dependent tasks.
Example:
Software build dependencies:
Database
↓
Backend
↓
Frontend
Correct order:
Database → Backend → Frontend
Real Examples
- Build systems
- Course prerequisites
- Deployment pipelines
Algorithm: Kahn's Algorithm
Uses:
- indegree count
- queue
Example:
A → C
B → C
Indegree:
A = 0
B = 0
C = 2
Start:
A,B
Remove:
C becomes 0
Python:
from collections import deque
def topological_sort(graph):
indegree = {}
for node in graph:
indegree[node] = 0
for node in graph:
for neighbor in graph[node]:
indegree[neighbor] += 1
queue = deque(
[n for n in indegree if indegree[n] == 0]
)
result=[]
while queue:
node=queue.popleft()
result.append(node)
for neighbor in graph[node]:
indegree[neighbor]-=1
if indegree[neighbor]==0:
queue.append(neighbor)
return result
Complexity:
Time:
O(V+E)
Space:
O(V)
Senior Answer
Topological sorting is used to order dependent tasks in a directed acyclic graph. It is common in build systems, scheduling, and deployment pipelines.
24. What is Dijkstra's Algorithm?
Interview Answer
Dijkstra's algorithm finds the shortest path from one node to all other nodes in a weighted graph with non-negative weights.
Example:
A ----5---- B
| |
2 1
| |
C ----3---- D
Find shortest path from A.
It calculates:
A → C = 2
A → B = 5
A → C → D = 5
Uses
- GPS navigation
- network routing
- delivery systems
Algorithm
Uses:
Priority Queue (Min Heap)
Steps:
- Start from source
- Pick closest unvisited node
- Update distances
- Repeat
Python:
import heapq
def dijkstra(graph, start):
distances = {
node: float('inf')
for node in graph
}
distances[start]=0
heap=[(0,start)]
while heap:
current_distance,node=heapq.heappop(heap)
for neighbor,weight in graph[node]:
distance=current_distance+weight
if distance < distances[neighbor]:
distances[neighbor]=distance
heapq.heappush(
heap,
(distance,neighbor)
)
return distances
Complexity:
Using heap:
O((V+E) log V)
Senior Answer
Dijkstra uses a priority queue to repeatedly select the closest node and relax its edges. It is efficient for shortest-path problems with non-negative weights.
25. What is a Heap / Priority Queue?
Interview Answer
A heap is a tree-based data structure used to quickly retrieve the minimum or maximum element.
Types:
Min Heap
Smallest element at the top.
Example:
1
/ \
3 5
Max Heap
Largest element at the top.
Example:
10
/ \
7 5
Python
Python provides:
import heapq
Min heap:
heap=[]
heapq.heappush(heap,5)
heapq.heappush(heap,2)
heapq.heappop(heap)
Returns:
2
Applications
- priority queues
- Dijkstra
- scheduling
- finding top K elements
Complexity
Insert:
O(log n)
Remove:
O(log n)
Get minimum:
O(1)
Senior Answer
A heap provides efficient access to the highest or lowest priority element. I use it for scheduling, priority processing, and algorithms like Dijkstra.
26. How do you find the Kth Largest Element?
Problem
Input:
nums=[3,2,1,5,6,4]
k=2
Output:
5
because:
6,5,4,3,2,1
^
second largest
Solution 1: Sorting
def kth_largest(nums,k):
nums.sort(reverse=True)
return nums[k-1]
Complexity:
Time:
O(n log n)
Better Solution: Min Heap
Keep only k elements.
import heapq
def kth_largest(nums,k):
heap=[]
for n in nums:
heapq.heappush(heap,n)
if len(heap)>k:
heapq.heappop(heap)
return heap[0]
Example:
k=2
Maintain:
largest two numbers
Complexity:
Time:
O(n log k)
Space:
O(k)
Senior Answer
For large datasets, I prefer a min heap because it avoids sorting the entire collection and maintains only the k largest elements.
27. What is an LRU Cache?
Interview Answer
LRU means:
Least Recently Used
It removes the item that has not been accessed for the longest time.
Example:
Cache size:
3
Operations:
Add A
Add B
Add C
Access A
Add D
Cache:
B C A
B is removed because it was least recently used.
Implementation
LRU requires:
- Hash Map
For O(1) lookup.
- Doubly Linked List
For O(1) insertion/removal.
Architecture:
Hash Map
|
Node addresses
|
Doubly Linked List
Python:
from collections import OrderedDict
class LRUCache:
def __init__(self, capacity):
self.cache=OrderedDict()
self.capacity=capacity
def get(self,key):
if key not in self.cache:
return -1
value=self.cache.pop(key)
self.cache[key]=value
return value
def put(self,key,value):
if key in self.cache:
self.cache.pop(key)
self.cache[key]=value
if len(self.cache)>self.capacity:
self.cache.popitem(last=False)
Uses
- web caching
- database caching
- API response caching
Senior Answer
LRU Cache combines a hash map for fast lookup and a doubly linked list for tracking usage order, achieving O(1) get and put operations.
28. What is Backtracking?
Interview Answer
Backtracking is a technique where we build a solution step by step and undo choices when they lead to invalid results.
Pattern:
Choose
↓
Explore
↓
Undo
Example:
Generate permutations:
Input:
[1,2,3]
Output:
123
132
213
231
312
321
Algorithm:
def backtrack(path):
if complete(path):
result.append(path.copy())
return
for choice in choices:
path.append(choice)
backtrack(path)
path.pop()
Applications
- Sudoku
- N-Queens
- permutations
- combinations
- maze solving
Senior Answer
Backtracking explores possible solutions recursively and removes invalid choices. It is useful for problems involving combinations, permutations, and constraint solving.
29. Generate Permutations
Problem
Input:
[1,2,3]
Return:
[
[1,2,3],
[1,3,2],
[2,1,3],
...
]
Solution:
def permutations(nums):
result=[]
def backtrack(path,used):
if len(path)==len(nums):
result.append(path.copy())
return
for i in range(len(nums)):
if i in used:
continue
used.add(i)
path.append(nums[i])
backtrack(path,used)
path.pop()
used.remove(i)
backtrack([],set())
return result
Complexity:
Number of permutations:
n!
Time:
O(n!)
Space:
O(n)
Senior Answer
Permutations are a classic backtracking problem where each recursive call chooses an unused element and explores remaining possibilities.
30. What are common algorithm patterns?
Interview Answer
Most coding interview problems follow recognizable patterns.
Pattern 1: Hash Map
Use when:
- lookup is needed
Examples:
- Two Sum
- Frequency counting
Pattern 2: Two Pointers
Use when:
- array is sorted
- comparing elements
Examples:
- pair sum
- palindrome
Pattern 3: Sliding Window
Use for:
- subarrays
- substrings
Examples:
- longest substring
Pattern 4: Fast/Slow Pointer
Use for:
- linked lists
- cycles
Examples:
- cycle detection
Pattern 5: BFS/DFS
Use for:
- trees
- graphs
Pattern 6: Dynamic Programming
Use when:
- overlapping subproblems exist
Senior Answer
I first identify the problem pattern before coding. Recognizing patterns such as hashing, sliding window, DFS, BFS, and dynamic programming allows me to create efficient solutions faster.
End of Chapter 13 — LeetCode & Algorithms
Covered:
✅ Graphs
✅ Graph Traversal
✅ Topological Sort
✅ Dijkstra
✅ Heap / Priority Queue
✅ Kth Largest Element
✅ LRU Cache
✅ Backtracking
✅ Permutations
✅ Algorithm Patterns
This section focuses on Dynamic Programming, Greedy Algorithms, and Interval Problems.
31. What is Dynamic Programming (DP)?
Interview Answer
Dynamic Programming is an optimization technique used when a problem has:
- Overlapping subproblems
- Optimal substructure
Instead of solving the same problem repeatedly, we store previous results.
Example: Fibonacci
Mathematical definition:
F(n) = F(n-1) + F(n-2)
Example:
F(5)
F5
/ \
F4 F3
/ \ / \
F3 F2 F2 F1
Notice:
F3
F2
are calculated multiple times.
Without DP
Recursive solution:
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
Complexity:
Time: O(2^n)
Space: O(n)
Very slow.
With Memoization
Store previous answers:
def fib(n, memo={}):
if n in memo:
return memo[n]
if n <= 1:
return n
memo[n] = fib(n-1,memo) + fib(n-2,memo)
return memo[n]
Complexity:
Time: O(n)
Space: O(n)
Two DP Approaches
1. Top-down
Recursion + cache.
Called:
Memoization
2. Bottom-up
Build answers iteratively.
Called:
Tabulation
Example:
0 1 1 2 3 5 8
Senior Answer
Dynamic programming improves performance by storing results of overlapping subproblems. I identify the state, recurrence relation, and base cases before implementing the solution.
32. How do you recognize a Dynamic Programming problem?
Interview Answer
I look for these characteristics:
1. Repeated Calculations
Example:
Fibonacci
The same values are calculated multiple times.
2. Choice Problems
Example:
"Maximum profit"
Choices:
Take item
Skip item
3. Optimization Questions
Common words:
- maximum
- minimum
- longest
- shortest
- best possible
Examples
Fibonacci
State:
dp[i] = Fibonacci number at i
Coin Change
State:
dp[amount] = minimum coins needed
Longest Common Subsequence
State:
dp[i][j]
=
answer using first i and j characters
Senior Answer
I identify DP problems by looking for overlapping subproblems and optimization decisions. The key step is defining the state and transition formula.
33. Solve Climbing Stairs Problem
Problem
You can climb:
1 or 2 steps
How many ways to reach step n?
Example:
n = 5
Answer:
8
Thinking
For step 5:
You can arrive from:
step 4 + 1
or
step 3 + 2
Therefore:
ways(n)=ways(n-1)+ways(n-2)
Solution
def climb_stairs(n):
if n <= 2:
return n
prev2 = 1
prev1 = 2
for i in range(3,n+1):
current = prev1 + prev2
prev2 = prev1
prev1 = current
return prev1
Complexity:
Time: O(n)
Space: O(1)
Senior Answer
This is a Fibonacci-style DP problem. Each state depends only on the previous two states, allowing optimization from O(n) memory to O(1).
34. What is the 0/1 Knapsack problem?
Interview Answer
The Knapsack problem asks:
Given items with:
- weight
- value
Choose items to maximize value without exceeding capacity.
Example:
Capacity:
10 kg
Items:
Item | Weight | Value |
A | 5 | 50 |
B | 4 | 40 |
C | 6 | 60 |
Choose the best combination.
Decision
For each item:
Two choices:
Take it
or
Skip it
DP State
dp[i][capacity]
means:
maximum value using first i items.
Formula
If item too heavy:
dp[i][w]=dp[i-1][w]
Otherwise:
max(
skip item,
take item
)
Complexity
Time: O(n * capacity)
Space: O(n * capacity)
Senior Answer
Knapsack is a classic DP problem where each item creates a decision: include or exclude. The solution stores the best result for each item and capacity combination.
35. What is Coin Change?
Problem
Given coins:
[1,2,5]
Amount:
11
Find minimum coins.
Answer:
3
5 + 5 + 1
DP Idea
State:
dp[x]
minimum coins needed for amount x
Example:
dp[0]=0
dp[1]=1
dp[2]=1
dp[5]=1
Python
def coin_change(coins, amount):
dp=[float('inf')] * (amount+1)
dp[0]=0
for value in range(1,amount+1):
for coin in coins:
if value >= coin:
dp[value]=min(
dp[value],
dp[value-coin]+1
)
return -1 if dp[amount]==float('inf') else dp[amount]
Complexity:
Time: O(amount * coins)
Space: O(amount)
Senior Answer
Coin Change uses bottom-up dynamic programming where each amount stores the minimum number of coins required to reach it.
36. What is the Longest Common Subsequence (LCS)?
Interview Answer
LCS finds the longest sequence that appears in two strings in the same order.
Characters do not need to be adjacent.
Example:
String 1:
"abcde"
String 2:
"ace"
Answer:
ace
DP State
dp[i][j]
means:
LCS length between:
first i characters
first j characters
Transition
If characters match:
dp[i][j]=dp[i-1][j-1]+1
Otherwise:
max(
dp[i-1][j],
dp[i][j-1]
)
Complexity
Time: O(m*n)
Space: O(m*n)
Applications
- file comparison
- DNA analysis
- version control
Senior Answer
LCS is a two-dimensional DP problem where the state represents the best solution for prefixes of two sequences.
37. What is the Longest Increasing Subsequence (LIS)?
Problem
Find the longest increasing sequence.
Example:
[10,9,2,5,3,7,101]
Answer:
[2,3,7,101]
Length:
4
DP Idea
Define:
dp[i]
as:
length of LIS ending at index i
Example:
For:
[2,5,3]
At 5:
2 → 5
length=2
At 3:
2 → 3
length=2
Complexity
Basic DP:
O(n²)
Optimized:
O(n log n)
using binary search.
Senior Answer
LIS can be solved using dynamic programming by tracking the best increasing subsequence ending at each position. An optimized approach uses binary search.
38. What are Interval Problems?
Interview Answer
Interval problems involve ranges:
[start, end]
Examples:
Meetings
Reservations
Time schedules
Example:
[1,3]
[5,8]
[10,12]
Common techniques:
- Sort intervals
- Compare neighbors
- Merge or detect conflicts
Typical Problems
- Merge intervals
- Meeting rooms
- Insert interval
- Employee free time
Senior Answer
Interval problems are usually solved by sorting ranges by their start value and then processing overlapping intervals sequentially.
39. Solve Merge Intervals
Problem
Input:
[
[1,3],
[2,6],
[8,10],
[15,18]
]
Output:
[
[1,6],
[8,10],
[15,18]
]
Approach
Sort:
[1,3]
[2,6]
[8,10]
Compare:
Current:
1-3
Next:
2-6
They overlap:
merge
Python
def merge(intervals):
intervals.sort()
result=[]
for interval in intervals:
if not result or result[-1][1] < interval[0]:
result.append(interval)
else:
result[-1][1] = max(
result[-1][1],
interval[1]
)
return result
Complexity:
Time: O(n log n)
Space: O(n)
Senior Answer
For interval merging, I sort intervals by start time and merge whenever the current interval overlaps with the previous result.
40. What is a Greedy Algorithm?
Interview Answer
A greedy algorithm makes the best local choice at each step hoping it leads to the global optimum.
Example:
Making change:
Amount:
£37
Coins:
£20 £10 £5 £2 £1
Greedy approach:
Take largest possible coin first:
20 + 10 + 5 + 2
Greedy Works When:
The problem has:
- greedy choice property
- optimal substructure
Examples
Activity Selection
Choose maximum non-overlapping meetings.
Huffman Coding
Compression algorithm.
Dijkstra
For non-negative weights.
When Greedy Fails
Example:
Coins:
[1,3,4]
Amount:
6
Greedy:
4+1+1
3 coins.
Optimal:
3+3
2 coins.
Senior Answer
Greedy algorithms make locally optimal decisions. They are efficient but require proof that local choices lead to the global optimum.
End of Chapter 13 — LeetCode & Algorithms
Covered:
✅ Dynamic Programming
✅ Memoization
✅ Tabulation
✅ Fibonacci Pattern
✅ Climbing Stairs
✅ Knapsack
✅ Coin Change
✅ LCS
✅ LIS
✅ Interval Problems
✅ Merge Intervals
✅ Greedy Algorithms
41. What is Prefix Sum?
Interview Answer
Prefix Sum is a technique where we preprocess an array so that range sum calculations can be performed efficiently.
Example:
Original array:
[2,4,6,8,10]
Create prefix array:
[0,2,6,12,20,30]
Meaning:
prefix[i] = sum of elements before i
Finding Range Sum
Question:
Find sum from index 1 to 3.
Original:
[2,4,6,8,10]
Need:
4+6+8 = 18
Using prefix:
prefix[4] - prefix[1]
20 - 2 = 18
Python
def build_prefix(nums):
prefix=[0]
for n in nums:
prefix.append(prefix[-1]+n)
return prefix
Complexity:
Building:
O(n)
Query:
O(1)
Applications
- Range sum queries
- Subarray problems
- Running totals
- Financial calculations
Senior Answer
Prefix sums trade memory for speed. By preprocessing cumulative values, we can answer range queries in constant time.
42. Solve Subarray Sum Equals K
Problem
Given:
nums=[1,2,3]
k=3
Find number of continuous subarrays whose sum equals k.
Answer:
2
Because:
[1,2]
[3]
Brute Force
Check every subarray.
Complexity:
O(n²)
Optimized Solution
Use:
- prefix sum
- hash map
Idea:
If:
current_sum - previous_sum = k
then:
previous_sum = current_sum - k
Store previous sums.
Python
def subarray_sum(nums,k):
count=0
current=0
sums={0:1}
for n in nums:
current += n
if current-k in sums:
count += sums[current-k]
sums[current]=sums.get(current,0)+1
return count
Complexity:
Time:
O(n)
Space:
O(n)
Senior Answer
I use prefix sums with a hash map to avoid checking every possible subarray. This reduces the solution from quadratic to linear time.
43. Explain Kadane's Algorithm
Interview Answer
Kadane's algorithm finds the maximum sum contiguous subarray.
Problem:
[-2,1,-3,4,-1,2,1,-5,4]
Answer:
6
Because:
[4,-1,2,1]
Idea
At every position:
Choose:
- Start new subarray
- Continue previous subarray
Formula:
current =
max(
number,
current + number
)
Python
def max_sub_array(nums):
current=nums[0]
best=nums[0]
for n in nums[1:]:
current=max(
n,
current+n
)
best=max(
best,
current
)
return best
Complexity:
Time:
O(n)
Space:
O(1)
Applications
- Stock analysis
- Signal processing
- Maximum profit calculations
Senior Answer
Kadane's algorithm solves maximum subarray problems by maintaining the best possible sum ending at each position.
44. Solve Product of Array Except Self
Problem
Input:
[1,2,3,4]
Output:
[24,12,8,6]
Because:
24 = 2*3*4
12 = 1*3*4
Important Constraint
Do not use division.
Approach
Calculate:
- Product of elements on the left
- Product of elements on the right
Example:
Left:
[1,1,2,6]
Right:
[24,12,4,1]
Multiply:
[24,12,8,6]
Python
def product_except_self(nums):
result=[1]*len(nums)
prefix=1
for i in range(len(nums)):
result[i]=prefix
prefix*=nums[i]
suffix=1
for i in range(len(nums)-1,-1,-1):
result[i]*=suffix
suffix*=nums[i]
return result
Complexity:
Time:
O(n)
Space:
O(1)
(excluding output array)
Senior Answer
I solve this using prefix and suffix products, avoiding division and maintaining linear time complexity.
45. Solve Trapping Rain Water
Problem
Given heights:
0,1,0,2,1,0,1,3,2,1,2,1
Calculate trapped water.
Answer:
6
Idea
Water depends on:
min(left maximum, right maximum) - height
Example:
Left wall Right wall
|
|
| | |
|~~~~|
__|____|__
Two Pointer Solution
Maintain:
- left pointer
- right pointer
- left max
- right max
Python
def trap(height):
left=0
right=len(height)-1
left_max=0
right_max=0
water=0
while left < right:
if height[left] < height[right]:
if height[left]>=left_max:
left_max=height[left]
else:
water += left_max-height[left]
left+=1
else:
if height[right]>=right_max:
right_max=height[right]
else:
water += right_max-height[right]
right-=1
return water
Complexity:
Time:
O(n)
Space:
O(1)
Senior Answer
The two-pointer approach works because the smaller side determines the maximum possible trapped water.
46. What is a Trie?
Interview Answer
A Trie is a tree structure used for storing strings efficiently.
It is also called:
Prefix Tree
Example:
Words:
cat
car
can
Stored as:
c
|
a
/ | \
t r n
Uses
- autocomplete
- spell checking
- dictionary search
- search suggestions
Complexity
Searching:
O(length of word)
Insertion:
O(length of word)
Python Structure
class TrieNode:
def __init__(self):
self.children={}
self.end=False
Senior Answer
A Trie stores strings by characters and provides fast prefix-based searching. It is commonly used for autocomplete and dictionary applications.
47. What is Backtracking vs Dynamic Programming?
Interview Answer
Both solve complex problems recursively, but they solve different types of problems.
Backtracking
Goal:
Find all possible solutions.
Example:
Generate all permutations
Pattern:
Choose
Explore
Undo
Dynamic Programming
Goal:
Find optimal solution.
Example:
Minimum coins
Maximum profit
Pattern:
Store previous results
Comparison:
Backtracking | DP | |
Goal | Explore possibilities | Optimize |
Stores results | Usually no | Yes |
Examples | Sudoku | Coin Change |
Speed | Often exponential | Usually faster |
Senior Answer
Backtracking explores possible solutions, while dynamic programming avoids repeated calculations by storing optimal results of subproblems.
48. Explain Bit Manipulation.
Interview Answer
Bit manipulation works directly with binary representations of numbers.
Common operators:
Operator | Meaning |
& | AND |
| | OR |
^ | XOR |
<< | Shift left |
>> | Shift right |
Example: XOR
Property:
a ^ a = 0
a ^ 0 = a
Single Number Problem
Input:
[4,1,2,1,2]
Output:
4
Because duplicate numbers cancel.
Solution:
def single_number(nums):
result=0
for n in nums:
result ^= n
return result
Complexity:
Time:
O(n)
Space:
O(1)
Applications
- permissions
- flags
- compression
- low-level optimization
Senior Answer
Bit manipulation allows efficient operations at the binary level. XOR is especially useful for problems involving duplicates because equal values cancel each other.
49. What is a Monotonic Stack?
Interview Answer
A monotonic stack maintains elements in increasing or decreasing order.
It is useful for finding:
- next greater element
- previous smaller element
- temperature problems
Example:
Daily temperatures:
73,74,75,71,69,72,76,73
Find days until warmer temperature.
Idea
Keep indexes whose answer is not found yet.
When a warmer temperature appears:
Resolve previous items.
Python
def daily_temperatures(temp):
stack=[]
result=[0]*len(temp)
for i,t in enumerate(temp):
while stack and t > temp[stack[-1]]:
index=stack.pop()
result[index]=i-index
stack.append(i)
return result
Complexity:
Time:
O(n)
Space:
O(n)
Senior Answer
A monotonic stack maintains ordered elements and allows solving next greater or smaller element problems efficiently in linear time.
50. What are the most important LeetCode patterns for interviews?
Interview Answer
I focus on recognizing patterns rather than memorizing solutions.
Pattern Checklist
Arrays
Problems:
- Two Sum
- Product Except Self
- Maximum Subarray
Techniques:
- hashing
- prefix sum
- two pointers
Strings
Problems:
- Valid Parentheses
- Longest Substring
Techniques:
- stack
- sliding window
Linked Lists
Problems:
- Reverse List
- Detect Cycle
Techniques:
- pointers
Trees
Problems:
- Traversal
- Lowest Common Ancestor
Techniques:
- DFS
- BFS
Graphs
Problems:
- Shortest Path
- Dependencies
Techniques:
- BFS
- DFS
- Dijkstra
- Topological Sort
Optimization
Problems:
- Coin Change
- Knapsack
Technique:
- Dynamic Programming
Senior Answer
In interviews, I first identify the underlying pattern. Knowing common techniques like hashing, sliding window, DFS, BFS, dynamic programming, and greedy algorithms allows me to solve unfamiliar problems efficiently.
End of Chapter 13 — LeetCode & Algorithms
Covered:
✅ Prefix Sum
✅ Subarray Sum
✅ Kadane Algorithm
✅ Product Except Self
✅ Trapping Rain Water
✅ Trie
✅ Backtracking vs DP
✅ Bit Manipulation
✅ Monotonic Stack
✅ Interview Pattern Recognition
Chapter 13 — LeetCode & Algorithms Interview Questions
This final section covers senior-level algorithm design questions that are often asked after basic LeetCode problems.
51. How do you choose the right data structure?
Interview Answer
I choose a data structure based on:
- How data is accessed
- Required operations
- Performance requirements
Common Choices
Array / List
Use when:
- ordered data
- fast index access
Example:
numbers[5]
Complexity:
Access: O(1)
Search: O(n)
Hash Map
Use when:
- fast lookup by key
Example:
users["john"]
Complexity:
Average lookup: O(1)
Stack
Use when:
- last item processed first
Examples:
- recursion
- undo functionality
- parentheses validation
Queue
Use when:
- first item processed first
Examples:
- message processing
- task scheduling
Heap
Use when:
- need minimum/maximum quickly
Examples:
- priority queues
- top K problems
Tree
Use when:
- hierarchical relationships
Examples:
- file systems
- databases
Graph
Use when:
- relationships between entities
Examples:
- maps
- social networks
Senior Answer
I select data structures based on the operations that are most important. For example, I use hash maps for fast lookup, heaps for priority processing, and graphs for relationship-based problems.
52. Explain Sorting Algorithms and Their Differences
Interview Answer
Sorting algorithms differ in:
- time complexity
- memory usage
- stability
Bubble Sort
Repeatedly swaps adjacent elements.
Example:
5 3 2
swap
3 5 2
swap
3 2 5
Complexity:
O(n²)
Rarely used.
Selection Sort
Find smallest element and place it correctly.
Complexity:
O(n²)
Insertion Sort
Builds sorted section gradually.
Good for:
- nearly sorted data
Complexity:
O(n²)
Merge Sort
Divide and conquer.
Complexity:
O(n log n)
Memory:
O(n)
Quick Sort
Choose pivot and partition.
Average:
O(n log n)
Worst:
O(n²)
Heap Sort
Uses heap.
Complexity:
O(n log n)
Comparison
Algorithm | Average | Memory | Stable |
Bubble | O(n²) | O(1) | Yes |
Insertion | O(n²) | O(1) | Yes |
Merge | O(n log n) | O(n) | Yes |
Quick | O(n log n) | O(log n) | No |
Heap | O(n log n) | O(1) | No |
Senior Answer
In production applications I usually rely on optimized library sorting implementations, but understanding algorithms helps choose the right approach when constraints are unusual.
53. What is Quick Sort?
Interview Answer
Quick Sort is a divide-and-conquer sorting algorithm.
It works by:
- Choosing a pivot
- Partitioning elements around pivot
- Recursively sorting partitions
Example:
Array:
[7,2,9,1,5]
Choose pivot:
5
Partition:
[2,1] 5 [7,9]
Sort sides:
[1,2,5,7,9]
Complexity
Average:
O(n log n)
Worst:
O(n²)
Example:
Already sorted array with bad pivot choice.
Senior Answer
Quick Sort is efficient because partitioning reduces the problem size recursively. In practice, randomized pivots avoid worst-case behavior.
54. What is Binary Search Tree validation?
Problem
Determine whether a tree is a valid BST.
Example:
Valid:
5
/ \
3 8
Invalid:
5
/ \
7 8
Approach
Each node must satisfy:
left < node < right
Python:
def validate(node, low=float("-inf"), high=float("inf")):
if not node:
return True
if node.value <= low or node.value >= high:
return False
return (
validate(node.left, low, node.value)
and
validate(node.right, node.value, high)
)
Complexity:
Time:
O(n)
Space:
O(h)
Senior Answer
BST validation requires maintaining valid value ranges while traversing the tree recursively.
55. What is Lowest Common Ancestor (LCA)?
Interview Answer
The Lowest Common Ancestor is the deepest node that contains two given nodes in its subtree.
Example:
6
/ \
2 8
/ \
0 4
LCA of:
0 and 4
is:
2
Recursive Solution
def lowest_common_ancestor(root,p,q):
if not root or root == p or root == q:
return root
left = lowest_common_ancestor(
root.left,p,q
)
right = lowest_common_ancestor(
root.right,p,q
)
if left and right:
return root
return left or right
Complexity:
Time:
O(n)
Space:
O(h)
Senior Answer
LCA can be solved recursively by searching both subtrees. If both sides contain the target nodes, the current node is the ancestor.
56. Explain Rate Limiting Algorithm
Interview Answer
A rate limiter controls how many requests a client can make during a period.
Example:
API rule:
100 requests per minute
Common Algorithms
Token Bucket
Tokens are added over time.
Example:
Bucket capacity: 100 tokens
Each request consumes 1 token
If no tokens:
Request rejected
Sliding Window
Track requests in time window.
Example:
10:00:01
10:00:05
10:00:10
Fixed Window
Simple counter:
10:00-10:01
count requests
Enterprise Example
API Gateway:
Client
|
Rate Limiter
|
Backend Service
Senior Answer
Rate limiting protects services from overload. Common approaches include token bucket, fixed window, and sliding window algorithms.
57. Explain Producer-Consumer Pattern
Interview Answer
Producer-consumer is a concurrency pattern where:
- producers create data
- consumers process data
A queue connects them.
Architecture:
Producer
|
Queue
|
Consumer
Example:
Order processing:
Producer:
Customer places order
Queue:
RabbitMQ / Kafka
Consumer:
Payment service
Python example:
from queue import Queue
queue = Queue()
# Producer
queue.put("Order1")
# Consumer
order = queue.get()
Benefits
- decoupling
- scalability
- asynchronous processing
Senior Answer
Producer-consumer separates data creation from processing. Message queues allow systems to scale independently and handle spikes.
58. How do you design a Cache?
Interview Answer
A cache stores frequently accessed data closer to the application to improve performance.
Architecture:
User
|
Application
|
Cache
|
Database
Cache Strategies
Cache Aside
Application checks cache first.
Flow:
Request
|
Cache?
|
Yes → Return
|
No
|
Database
|
Store Cache
Write Through
Write to:
Cache + Database
Write Behind
Write cache first.
Database updated later.
Cache Considerations
- expiration
- invalidation
- consistency
- memory limits
Examples
- Redis
- Memcached
- CDN
Senior Answer
A cache improves performance by reducing expensive database calls. The main design challenges are cache invalidation, expiration policies, and consistency.
59. Explain Thread Safety in Algorithms
Interview Answer
Thread safety means multiple threads can access shared data without causing incorrect results.
Problem:
Two threads:
Counter = 0
Thread A:
Counter++
Thread B:
Counter++
Expected:
2
Possible result:
1
because operations overlap.
Solutions
Locks
Only one thread modifies data.
Atomic Operations
CPU guarantees operation completion.
Immutable Objects
Cannot change after creation.
Concurrent Collections
Examples:
.NET:
ConcurrentDictionary<TKey,TValue>
Senior Answer
Thread safety requires protecting shared state through synchronization mechanisms such as locks, atomic operations, immutable objects, or concurrent collections.
60. How do you approach a coding interview problem?
Interview Answer
My approach:
Step 1 — Understand the Problem
Clarify:
- input
- output
- constraints
- edge cases
Step 2 — Identify Pattern
Ask:
Is this:
- Hash Map?
- Two pointers?
- Sliding window?
- DFS/BFS?
- Dynamic programming?
Step 3 — Explain Solution
Before coding:
Example:
I will use a hash map because I need constant-time lookup.
Step 4 — Implement Clean Code
Focus on:
- meaningful names
- readability
- edge cases
Step 5 — Analyze Complexity
Always explain:
Time Complexity: O(n)
Space Complexity: O(n)
Step 6 — Test
Check:
- empty input
- one element
- duplicates
- large input
Senior Answer
I first understand constraints, identify the appropriate algorithm pattern, explain the trade-offs, implement clean code, and validate complexity and edge cases.
Chapter 13 — LeetCode & Algorithms Completed ✅
Total:
60 Interview Questions
Covered:
Fundamentals
✅ Big-O
✅ Complexity Analysis
✅ Data Structures
Arrays
✅ Two Sum
✅ Sliding Window
✅ Prefix Sum
✅ Kadane Algorithm
✅ Product Except Self
Linked Lists
✅ Reverse List
✅ Cycle Detection
Trees
✅ DFS
✅ BFS
✅ BST
✅ LCA
Graphs
✅ Traversal
✅ Topological Sort
✅ Dijkstra
Advanced
✅ Heap
✅ LRU Cache
✅ Trie
✅ Backtracking
✅ Dynamic Programming
✅ Greedy Algorithms
✅ Bit Manipulation
✅ Rate Limiting
✅ Concurrency Patterns