Data Structures & Algorithms MCQs multiple-choice questions with answers & explanations
All 27 Data Structures & Algorithms quiz questions on one page. Pick an answer in your head, then open Show answer to check it and read why. Want a score and a timer? Take them as a quiz instead.
Official reference: MIT 6.006 Introduction to Algorithms
- 1.easy
What is the time complexity of
f(n)?def f(n): count = 0 for i in range(n): j = 1 while j < n: j *= 2 count += 1 return count- A
O(n) - B
O(n log n) - C
O(n²) - D
O(n² log n)
Show answer
Answer: B (
O(n log n))The inner loop doubles
juntil it reachesn, so it runs aboutlog₂ ntimes. It runs once for each of thenouter iterations, givingO(n log n). It would beO(n²)only ifjincreased by a constant step. - A
- 2.easy
What is the time complexity of this loop?
total = 0 for i in range(n): for j in range(i, n): total += 1- A
O(n log n) - B
O(n) - C
O(n²) - D
O(2ⁿ)
Show answer
Answer: C (
O(n²))The inner loop runs
n, thenn - 1, down to1times, which sums ton(n + 1) / 2. Dropping the constant factor leavesO(n²). Starting the inner loop atihalves the work but does not change the growth rate. - A
- 3.hard
What is the time complexity of
g(n)?def g(n): i = n while i > 0: for _ in range(i): pass # O(1) work i //= 2- A
O(n log n) - B
O(log n) - C
O(n²) - D
O(n)
Show answer
Answer: D (
O(n))The outer loop runs
log ntimes, but the inner work shrinks each time:n + n/2 + n/4 + ..., a geometric series below2n. So the total isO(n), notO(n log n). Multiplying the iteration counts only works when the inner cost is the same on every pass. - A
- 4.easy
A dynamic array doubles its capacity whenever it is full. What is the amortized cost of one append?
- A
O(1) - B
O(log n) - C
O(n) - D
O(n log n)
Show answer
Answer: A (
O(1))A resize copies all elements, but because capacity doubles, the copies over
nappends total less than2n. Spread across all appends, each costsO(1)amortized. A single append that triggers a resize is stillO(n). - A
- 5.mid
What is the worst-case auxiliary space of this function on a binary tree with
nnodes?def tree_sum(node): if node is None: return 0 return node.val + tree_sum(node.left) + tree_sum(node.right)- A
O(log n) - B
O(n) - C
O(1) - D
O(n log n)
Show answer
Answer: B (
O(n))No data structure is allocated, but each active call holds a stack frame, so space equals the maximum recursion depth. A skewed tree (a chain) has depth
n, givingO(n).O(log n)holds only for a balanced tree. - A
- 6.easy
Which operation is
O(1)on a singly linked list that stores only aheadpointer?- AAccess the element at index
i - BAppend a node at the tail
- CInsert a node at the head
- DDelete the last node
Show answer
Answer: C (Insert a node at the head)
Inserting at the head only creates a node and repoints
head. Index access and tail append must walk the list, and deleting the last node needs the second-to-last node, which also takes a full walk. A tail pointer would make appendsO(1), but not deleting the last node. - AAccess the element at index
- 7.easy
A hash table resolves collisions with linked-list chains and holds
nkeys. What is the worst-case time for a lookup?- A
O(1) - B
O(log n) - C
O(n log n) - D
O(n)
Show answer
Answer: D (
O(n))If every key hashes to the same bucket, the table degenerates into one linked list and a lookup scans all
nentries.O(1)is the average case with a good hash function and bounded load factor. Some implementations, like Java 8+HashMap, turn long chains into balanced trees to soften this. - A
- 8.mid
A queue is built from two stacks, moving elements from the input stack to the output stack only when the output stack is empty. What is the amortized cost of a dequeue?
- A
O(1) - B
O(log n) - C
O(n) - D
O(√n)
Show answer
Answer: A (
O(1))Each element is pushed, moved and popped at most once, so
noperations doO(n)total work:O(1)amortized each. One dequeue that triggers a transfer can takeO(n), which is the worst case for a single call, not the amortized cost. - A
- 9.mid
What is the time complexity of building a binary heap from
nunsorted elements with bottom-up heapify, asheapq.heapifydoes?- A
O(n log n) - B
O(log n) - C
O(n) - D
O(n²)
Show answer
Answer: C (
O(n))Sift-down costs at most the height of the node, and most nodes are near the bottom: half are leaves, a quarter have height 1, and so on. The total work sums to
O(n). Pushing the elements one by one would beO(n log n). - A
- 10.mid
To find the
klargest ofnnumbers, you scan them while keeping a min-heap of size at mostk. What is the time complexity?- A
O(n log n) - B
O(n + k) - C
O(k log n) - D
O(n log k)
Show answer
Answer: D (
O(n log k))Each of the
nelements causes at most one push and one pop on a heap of sizek, eachO(log k), forO(n log k)total. That beats sorting (O(n log n)) whenkis small, and it uses onlyO(k)memory. - A
- 11.mid
Which pair of data structures gives an LRU cache
O(1)getandput?- AMin-heap keyed by last access time
- BHash map and doubly linked list
- CBalanced BST and a sorted array
- DTwo stacks and a hash set
Show answer
Answer: B (Hash map and doubly linked list)
The hash map finds the node for a key in
O(1), and the doubly linked list keeps recency order, so a node can be moved to the front or evicted from the back inO(1). A heap ordered by access time would make each updateO(log n). - 12.easy
A trie stores
Nwords. How long does it take to check whether a word of lengthLis present?- A
O(L) - B
O(N) - C
O(L log N) - D
O(N · L)
Show answer
Answer: A (
O(L))A lookup follows one child link per character, so it takes
O(L)regardless of how many words are stored. That independence fromN, plus fast prefix queries, is the main reason to use a trie. - A
- 13.hard
With both union by rank and path compression, what is the amortized cost of a union-find operation?
- A
O(log n) - B
O(log log n) - C
O(α(n)) - D
O(√n)
Show answer
Answer: C (
O(α(n)))α(n)is the inverse Ackermann function, which is at most 4 for any practicaln, so operations are effectively constant. Either optimization alone gives only aboutO(log n). - A
- 14.easy
What does this print for the tree built below?
class Node: def __init__(self, val, left=None, right=None): self.val, self.left, self.right = val, left, right def walk(n): return [n.val] + walk(n.left) + walk(n.right) if n else [] root = Node(1, Node(2, Node(4), Node(5)), Node(3)) print(walk(root))- A
[1, 2, 4, 5, 3] - B
[4, 2, 5, 1, 3] - C
[4, 5, 2, 3, 1] - D
[1, 2, 3, 4, 5]
Show answer
Answer: A (
[1, 2, 4, 5, 3])walkrecords the node before its left and right subtrees, which is pre-order:1, then the whole left subtree2, 4, 5, then3.[4, 2, 5, 1, 3]would be in-order,[4, 5, 2, 3, 1]post-order, and[1, 2, 3, 4, 5]level-order. - A
- 15.easy
Which algorithm finds the path with the fewest edges between two vertices of an unweighted graph in
O(V + E)?- ADepth-first search
- BBreadth-first search
- CPrim's algorithm
- DTopological sort
Show answer
Answer: B (Breadth-first search)
BFS explores vertices in order of distance, so the first time it reaches a vertex is via a shortest path. DFS finds a path, but not necessarily the shortest. Prim builds a minimum spanning tree, and topological sort only orders a DAG.
- 16.mid
A directed graph has some negative edge weights but no negative cycles. Which algorithm reliably computes single-source shortest paths?
- ADijkstra's algorithm
- BBreadth-first search
- CBellman-Ford
- DPrim's algorithm
Show answer
Answer: C (Bellman-Ford)
Bellman-Ford relaxes every edge
V - 1times, which handles negative weights inO(V · E)and can also detect negative cycles. Dijkstra assumes a finalized vertex can never get cheaper, which negative edges break. BFS ignores weights, and Prim solves a different problem. - 17.mid
Kahn's topological sort runs on a directed graph with 6 vertices but outputs only 4 of them. What does that tell you?
- AThe graph contains a cycle
- BThe graph is disconnected
- CTwo vertices have no edges
- DThe graph has two sources
Show answer
Answer: A (The graph contains a cycle)
Vertices on a cycle never reach in-degree 0, so Kahn's algorithm can never output them. A disconnected DAG, isolated vertices and multiple sources are all still fully ordered, since each of those vertices eventually has in-degree 0.
- 18.easy
Which of these sorting algorithms is not stable in its standard form?
- AMerge sort
- BInsertion sort
- CCounting sort
- DHeapsort
Show answer
Answer: D (Heapsort)
Heapsort swaps the root with the last heap element, moving items long distances past equal keys, so their relative order is not preserved. Merge sort (taking from the left half on ties), insertion sort and counting sort are all stable.
- 19.hard
What is the tight asymptotic lower bound on the worst-case number of comparisons made by any comparison-based sort of
nitems?- A
Θ(n log n) - B
Θ(n) - C
Θ(n²) - D
Θ(n log log n)
Show answer
Answer: A (
Θ(n log n))A comparison sort is a binary decision tree that must have at least
n!leaves, so its height is at leastlog₂(n!), which isΘ(n log n). Merge sort and heapsort meet that bound. Counting and radix sort go faster only because they do not rely on comparisons. - A
- 20.mid
A quicksort always picks the first element as its pivot. What is its running time on an already sorted array of
ndistinct values?- A
O(n) - B
O(n log n) - C
O(log n) - D
O(n²)
Show answer
Answer: D (
O(n²))On sorted input the first element is the minimum, so every partition puts nothing on one side and
n - 1elements on the other. That givesn + (n - 1) + ... + 1comparisons,O(n²), with recursion depthn. Random or median-of-three pivots avoid this. - A
- 21.mid
What does this print for a sorted list containing duplicates?
from bisect import bisect_left, bisect_right a = [1, 2, 2, 2, 5, 7] print(bisect_left(a, 2), bisect_right(a, 2))- A
1 3 - B
1 4 - C
2 4 - D
0 3
Show answer
Answer: B (
1 4)bisect_leftreturns the first index whose value is>= 2, which is1.bisect_rightreturns the first index whose value is> 2, which is4, one past the last2. So the 2s occupy indices1to3, and there are4 - 1 = 3of them. - A
- 22.mid
This attempt at "longest substring without repeating characters" has a bug. What does it print?
def longest(s): last, start, best = {}, 0, 0 for i, ch in enumerate(s): if ch in last: start = last[ch] + 1 last[ch] = i best = max(best, i - start + 1) return best print(longest("abba"))- A
2 - B
3 - C
4 - D
1
Show answer
Answer: B (
3)At the second
b,startmoves to2. At the finala, the stale entrylast["a"] = 0movesstartback to1, so the window"bba"is counted as length3. The correct answer is2; the fix is to movestartonly whenlast[ch] >= start. - A
- 23.mid
With coins
[1, 3, 4]and amount6, how many coins does "always take the largest coin that fits" use, compared with the optimum?- AGreedy 2, optimal 2
- BGreedy 3, optimal 2
- CGreedy 3, optimal 3
- DGreedy 4, optimal 2
Show answer
Answer: B (Greedy 3, optimal 2)
Greedy takes
4, then1 + 1, for 3 coins, while3 + 3needs only 2. Greedy is not safe for arbitrary coin systems, which is why minimum coin change is solved with DP. - 24.hard
This is the
O(n log n)LIS technique. What does it print?from bisect import bisect_left tails = [] for x in [3, 5, 6, 2]: i = bisect_left(tails, x) if i == len(tails): tails.append(x) else: tails[i] = x print(tails, len(tails))- A
[2, 5, 6] 3 - B
[3, 5, 6] 3 - C
[2, 6] 2 - D
[2, 3, 5, 6] 4
Show answer
Answer: A (
[2, 5, 6] 3)After
3, 5, 6are appended,2replacestails[0], giving[2, 5, 6]. The length3is the correct LIS length, but[2, 5, 6]is not a real subsequence, because2comes last in the input. Onlylen(tails)is meaningful. - A
- 25.hard
In the 1D 0/1 knapsack DP,
dp[c] = max(dp[c], dp[c - w] + v), what goes wrong if capacitycis iterated upwards instead of downwards?- AThe result can only get smaller
- BIt fails only for zero-weight items
- CEach item may be used more than once
- DThe time becomes
O(n · W²)
Show answer
Answer: C (Each item may be used more than once)
Going upwards,
dp[c - w]may already include the current item, so it can be added again; that computes the unbounded knapsack. Iterating downwards reads only values from before this item was considered. The time staysO(n · W)either way. - 26.easy
For a positive integer
x, what does(x & (x - 1)) == 0tell you?- A
xis an odd number - B
xis divisible by 4 - C
xis a power of two - D
xhas every bit set
Show answer
Answer: C (
xis a power of two)x & (x - 1)clears the lowest set bit, so the result is zero only ifxhad exactly one set bit, meaningxis a power of two. Keep the parentheses in Java or C, where==binds tighter than&. - A
- 27.easy
What does this XOR reduction print?
from functools import reduce from operator import xor print(reduce(xor, [4, 1, 2, 1, 2]))- A
0 - B
10 - C
2 - D
4
Show answer
Answer: D (
4)XOR is commutative and associative,
a ^ a = 0anda ^ 0 = a, so the pairs of1and2cancel and only4remains. This finds the one unpaired value inO(n)time andO(1)space.10is the sum, not the XOR. - A