Skip to main content
All subjects

Data Structures & Algorithms FRQ practice

8 problems · Worked solutions · 9-point rubrics · Java

Code Scholars practice problems. These are not official exam prompts.

Problem 1 · Foundations and Analysis · 9 points

Count iterations in a shrinking loop

For nonnegative n, analyze the method below. Assume mathematical integers for the paper count; Java n is int.

  1. A. Derive the number of inner iterations when n is a power of two.
  2. B. Give a tight asymptotic time bound and auxiliary space.
  3. C. Explain why the nested loops are not quadratic and handle n = 0.
Show worked solution and rubric
public static long work(int n) {
    long count = 0;
    for (int size = n; size > 0; size /= 2)
        for (int j = 0; j < size; j++) count++;
    return count;
}
  1. A. For n=2^k, the inner counts are n,n/2,...,1. The total is 2n-1 by the finite geometric series formula.
  2. B. The total is Θ(n) for positive n and auxiliary space is O(1). For arbitrary n the floored series remains between n and 2n.
  3. C. The inner bound shrinks geometrically instead of staying n. For n=0, neither loop executes and the returned count is 0.

Scoring rubric

  • 3 points: For n=2^k, the inner counts are n,n/2,...,1
  • 3 points: The total is Θ(n) for positive n and auxiliary space is O(1)
  • 3 points: The inner bound shrinks geometrically instead of staying n
Review this unit

Problem 2 · Arrays, Strings, and Pattern Techniques · 9 points

Find the longest target-sum window

Implement longestSum(int[] a, long target) returning the length of the longest contiguous subarray whose sum equals target. Values may be negative. Empty input returns 0; a length-zero answer is allowed. Assume prefix sums and their differences fit long.

  1. A. Use prefix sums and a hash map of earliest indices.
  2. B. Trace [1,-1,5,-2,3] with target 3.
  3. C. Explain why a nonnegative sliding-window rule fails and analyze expected costs.
Show worked solution and rubric
public static int longestSum(int[] a, long target) {
    Map<Long,Integer> first = new HashMap<>();
    first.put(0L, -1);
    long prefix = 0;
    int best = 0;
    for (int i = 0; i < a.length; i++) {
        prefix += a[i];
        Integer j = first.get(prefix - target);
        if (j != null) best = Math.max(best, i - j);
        first.putIfAbsent(prefix, i);
    }
    return best;
}
  1. A. Store prefix zero at index -1. At index i, a prior prefix equal to current-target gives a valid subarray; keep its earliest index to maximize length.
  2. B. The first four elements sum to 3, giving length 4. The complete array sums to 6; no length-5 solution exists.
  3. C. Negative values can decrease a growing window sum, so moving one boundary by a sum comparison is unsound. Expected time O(n), map space O(n).

Scoring rubric

  • 3 points: Store prefix zero at index -1
  • 3 points: The first four elements sum to 3, giving length 4
  • 3 points: Negative values can decrease a growing window sum, so moving one boundary by a sum comparison is unsound
Review this unit

Problem 3 · Stacks, Queues, and Linked Structures · 9 points

Check nested delimiters

Implement balanced(String s) for parentheses, square brackets, and braces. Ignore all other characters; process basic Latin text.

bottom: (top: [next: )
Stack order after reading ([ is bottom (, top [. A closing ) mismatches the top.
  1. A. Use a stack to check matching type and nesting order.
  2. B. Trace "([x])" and "([)]".
  3. C. Explain the empty-stack check, final-stack check, and complexity.
Show worked solution and rubric
public static boolean balanced(String s) {
    Deque<Character> stack = new ArrayDeque<>();
    String opens = "([{", closes = ")]}", text = s;
    for (int i = 0; i < text.length(); i++) {
        char c = text.charAt(i);
        if (opens.indexOf(c) >= 0) stack.push(c);
        else {
            int k = closes.indexOf(c);
            if (k >= 0 && (stack.isEmpty() || stack.pop() != opens.charAt(k))) return false;
        }
    }
    return stack.isEmpty();
}
  1. A. Push opening delimiters. Each closing delimiter must match the most recent unmatched opener; pop only after checking that the stack is nonempty.
  2. B. ([x]) is true because [ pairs with ] before ( pairs with ). ([)] is false: ) arrives while [ is on top.
  3. C. A closer with no opener is invalid; leftover openers at the end are also invalid. Time O(n), worst-case stack O(n).

Scoring rubric

  • 3 points: Push opening delimiters
  • 3 points: ([x]) is true because [ pairs with ] before ( pairs with )
  • 3 points: A closer with no opener is invalid; leftover openers at the end are also invalid
Review this unit

Problem 4 · Hash Tables, Heaps, and Priority Structures · 9 points

Keep the kth largest value

Implement kthLargest(int[] a,int k), counting duplicates as separate values. Reject k<1 or k>a.length. Use a min-heap of at most k elements.

  1. A. Implement and state the heap invariant.
  2. B. Trace [5,1,5,3] for k = 2.
  3. C. Compare with sorting and state time and storage costs.
Show worked solution and rubric
public static int kthLargest(int[] a, int k) {
    if (k < 1 || k > a.length) throw new IllegalArgumentException("k");
    PriorityQueue<Integer> heap = new PriorityQueue<>();
    for (int value : a) {
        heap.add(value);
        if (heap.size() > k) heap.remove();
    }
    return heap.element();
}
  1. A. After each prefix, keep its largest min(k,prefix length) elements. If insertion creates k+1 entries, removing the minimum discards an element outside the largest k.
  2. B. After all values the heap contains [5,5], so the result is 5. Duplicates count independently.
  3. C. Each heap operation takes O(log(k+1)); total O(n log(k+1)), auxiliary O(k). Sorting all input is O(n log n) and may mutate the array.

Scoring rubric

  • 3 points: After each prefix, keep its largest min(k,prefix length) elements
  • 3 points: After all values the heap contains [5,5], so the result is 5
  • 3 points: Each heap operation takes O(log(k+1)); total O(n log(k+1)), auxiliary O(k)
Review this unit

Problem 5 · Trees and Balanced Search Structures · 9 points

Validate a strict binary search tree

A Node has int value and Node left,right. Implement validBst(Node root); duplicates are not allowed. Check global ancestry bounds, not just immediate children.

10512
Invalid BST: 12 is in the left subtree of 10, although it exceeds 10.
  1. A. Implement with open lower and upper bounds.
  2. B. Explain why root 10, left child 5, and left-right grandchild 12 is invalid.
  3. C. Explain integer endpoints and analyze balanced and skewed trees.
Show worked solution and rubric
public static class Node {
    int value; Node left, right;
    Node(int value) { this.value = value; }
}
public static boolean validBst(Node root) {
    return within(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
private static boolean within(Node node, long low, long high) {
    if (node == null) return true;
    if (node.value <= low || node.value >= high) return false;
    return within(node.left, low, node.value) && within(node.right, node.value, high);
}
  1. A. Pass an allowed open interval down the recursion: a left child inherits the lower bound and parent value as upper; a right child inherits parent value as lower.
  2. B. The value 12 belongs to the entire left subtree of 10 and must be below 10, even though it is above its own parent 5.
  3. C. Use long bounds to permit Integer.MIN_VALUE and MAX_VALUE as legitimate nodes. Time O(n), stack O(h): O(log n) balanced and O(n) skewed.

Scoring rubric

  • 3 points: Pass an allowed open interval down the recursion: a left child inherits the lower bound and parent value as upper; a right child inherits parent value as lower.
  • 3 points: The value 12 belongs to the entire left subtree of 10 and must be below 10, even though it is above its own parent 5.
  • 3 points: Use long bounds to permit Integer.MIN_VALUE and MAX_VALUE as legitimate nodes
Review this unit

Problem 6 · Graphs and Network Algorithms · 9 points

Order prerequisite tasks

A directed graph uses outgoing adjacency lists: u -> v means u must finish before v. Implement order(graph) returning a topological order, or an empty list if a cycle exists. For an empty graph, return an empty list.

  1. A. Implement Kahn’s algorithm with indegrees.
  2. B. Trace [[2],[2],[]] and [[1],[0]].
  3. C. Explain cycle detection and time/space costs.
Show worked solution and rubric
public static List<Integer> order(List<List<Integer>> graph) {
    int n = graph.size(); int[] indegree = new int[n];
    for (List<Integer> edges : graph) for (int v : edges) indegree[v]++;
    Queue<Integer> ready = new ArrayDeque<>();
    for (int v = 0; v < n; v++) if (indegree[v] == 0) ready.add(v);
    List<Integer> result = new ArrayList<>();
    while (!ready.isEmpty()) {
        int u = ready.remove(); result.add(u);
        for (int v : graph.get(u)) if (--indegree[v] == 0) ready.add(v);
    }
    return result.size() == n ? result : new ArrayList<>();
}
  1. A. Compute all indegrees, enqueue zero-indegree vertices, and remove their outgoing edges when processed. Enqueue a neighbor exactly when its indegree reaches zero.
  2. B. A valid first output is [0,1,2]. The second graph has a cycle and no initial zero-indegree vertex, so output is empty.
  3. C. If fewer than V vertices are removed, the remaining subgraph contains a directed cycle. Time O(V+E); indegrees, queue, and result occupy O(V).

Scoring rubric

  • 3 points: Compute all indegrees, enqueue zero-indegree vertices, and remove their outgoing edges when processed
  • 3 points: A valid first output is [0,1,2]
  • 3 points: If fewer than V vertices are removed, the remaining subgraph contains a directed cycle
Review this unit

Problem 7 · Sorting and Selection · 9 points

Merge two sorted arrays stably

Implement merge(int[] left,int[] right) returning a new sorted array. Both inputs are already nondecreasing. If values tie, choose the left value first. Assume their combined length fits an array.

  1. A. Implement the two-pointer merge.
  2. B. Trace left=[1,3,3], right=[2,3]. Label origins on paper.
  3. C. Explain stability, empty inputs, and costs.
Show worked solution and rubric
public static int[] merge(int[] left, int[] right) {
    int[] out = new int[left.length + right.length];
    int i = 0, j = 0, k = 0;
    while (i < left.length && j < right.length)
        out[k++] = left[i] <= right[j] ? left[i++] : right[j++];
    while (i < left.length) out[k++] = left[i++];
    while (j < right.length) out[k++] = right[j++];
    return out;
}
  1. A. Maintain pointers to the first unread item in each array. Choose <= from the left on a tie and copy the remaining tail after either input is exhausted.
  2. B. The origins are 1L,2R,3L,3L,3R. The values are [1,2,3,3,3]. The ordering inside each input is preserved.
  3. C. Choosing left on equality preserves relative order across consecutive sorted runs. Empty inputs copy the other input. Time O(n+m); output O(n+m), auxiliary workspace excluding output O(1).

Scoring rubric

  • 3 points: Maintain pointers to the first unread item in each array
  • 3 points: The origins are 1L,2R,3L,3L,3R
  • 3 points: Choosing left on equality preserves relative order across consecutive sorted runs
Review this unit

Problem 8 · Algorithm Design · 9 points

Minimize an exact coin count

Implement minCoins(int[] coins,int amount) for positive coin values and nonnegative amount. Unlimited copies are available. Return -1 if impossible. Assume amount <=10000.

  1. A. Give a bottom-up dynamic programming solution.
  2. B. Trace coins=[1,3,4], amount=6 and compare greedy.
  3. C. State the recurrence, base case, and complexity.
Show worked solution and rubric
public static int minCoins(int[] coins, int amount) {
    int[] dp = new int[amount + 1];
    Arrays.fill(dp, amount + 1); dp[0] = 0;
    for (int x = 1; x <= amount; x++)
        for (int c : coins) if (c <= x) dp[x] = Math.min(dp[x], dp[x - c] + 1);
    return dp[amount] > amount ? -1 : dp[amount];
}
  1. A. dp[x] is the minimum coins for exact amount x. Initialize dp[0]=0 and other entries to a sentinel amount+1; test every coin not exceeding x.
  2. B. The optimal answer is 2 using 3+3. Taking the largest first gives 4+1+1, so greedy uses 3 coins and is not optimal.
  3. C. The recurrence is dp[x]=min(dp[x-c]+1) over allowed coins c<=x. Time O(amount*number of coins), space O(amount). A sentinel final value means unreachable.

Scoring rubric

  • 3 points: dp[x] is the minimum coins for exact amount x
  • 3 points: The optimal answer is 2 using 3+3
  • 3 points: The recurrence is dp[x]=min(dp[x-c]+1) over allowed coins c<=x
Review this unit

Need help with this topic?

Work through questions with a tutor and get help with the steps you find difficult.

Get help with this topic