Recursive Searching and Sorting

Help Questions

AP Computer Science A › Recursive Searching and Sorting

Questions 1 - 10
1

For the recursive binary search method below, what is the time complexity of the given recursive algorithm?


public class Searcher {

    public static int binarySearch(int[] nums, int target, int low, int high) {

        if (low > high) {

            return -1;

        }

        int mid = (low + high) / 2;

        if (nums<u>mid</u> == target) {

            return mid;

        }

        if (target < nums<u>mid</u>) {

            return binarySearch(nums, target, low, mid - 1);

        } else {

            return binarySearch(nums, target, mid + 1, high);

        }

    }

}

$O(1)$ because it always checks the middle element.

$O(\log n)$ because it halves the search interval each call.

$O(n \log n)$ because it sorts while searching.

$O(n)$ because it may check every index once.

Explanation

This question tests AP Computer Science A skills on recursive searching and sorting algorithms, focusing on analyzing binary search's time complexity. Recursion involves functions calling themselves with modified parameters until a base case is reached, effectively breaking down a problem into smaller, manageable parts. In this problem, the binary search algorithm halves the search interval with each recursive call by adjusting either the low or high boundary based on the comparison with the middle element. Choice C is correct because binary search has O(log n) time complexity since each recursive call eliminates half of the remaining elements, requiring at most log₂(n) comparisons to find the target or determine it's not present. Choice A is incorrect because O(n) would mean checking every element, which only happens in the worst case of linear search, not binary search's efficient halving strategy. To help students: Show how a 16-element array requires at most 4 comparisons (log₂16 = 4). Create a table showing how the search space shrinks: 16→8→4→2→1, demonstrating the logarithmic pattern.

2

What is the time complexity of this recursive merge sort on an array of size $n$?


public class Sorter {

    public static void mergeSort(int[] nums, int left, int right) {

        if (left >= right) {

            return;

        }

        int mid = (left + right) / 2;

        mergeSort(nums, left, mid);

        mergeSort(nums, mid + 1, right);

        merge(nums, left, mid, right);

    }

    private static void merge(int[] nums, int left, int mid, int right) {

        int[] temp = new int<u>right - left + 1</u>;

        int i = left, j = mid + 1, k = 0;

        while (i <= mid && j <= right) {

            temp<u>k++</u> = (nums<u>i</u> <= nums<u>j</u>) ? nums<u>i++</u> : nums<u>j++</u>;

        }

        while (i <= mid) temp<u>k++</u> = nums<u>i++</u>;

        while (j <= right) temp<u>k++</u> = nums<u>j++</u>;

        for (int t = 0; t < temp.length; t++) nums<u>left + t</u> = temp<u>t</u>;

    }

}

$O(n \log n)$ because it splits and merges across levels.

$O(n^2)$ because it compares every pair of elements.

$O(n)$ because each element moves at most once.

$O(\log n)$ because it only splits the array.

Explanation

This question tests AP Computer Science A skills on recursive searching and sorting algorithms, focusing on analyzing the time complexity of recursive merge sort. Understanding merge sort's complexity requires analyzing both the recursive splitting and the merging phases. The algorithm creates a recursion tree with log n levels (since we halve the problem size at each level), and at each level, the merge operations collectively process all n elements. Choice D is correct because merge sort has O(n log n) time complexity: there are O(log n) levels in the recursion tree, and each level requires O(n) work to merge all segments at that level. Choice C is incorrect because O(n²) would imply nested loops comparing every pair, but merge sort's divide-and-conquer approach avoids this quadratic behavior. To help students: Draw the recursion tree showing how n elements are split into n single-element arrays across log n levels. Calculate the total work at each level (always n) and multiply by the number of levels (log n) to get n log n total operations.

3

For the recursive merge sort shown, what is the time complexity in terms of $n$ array elements?


public static void mergeSort(int[] nums, int left, int right) {

    if (left >= right) return;

    int mid = (left + right) / 2;

    mergeSort(nums, left, mid);

    mergeSort(nums, mid + 1, right);

    merge(nums, left, mid, right);

}

$O(\log n)$ because it halves the array each call

$O(n)$ because each element is visited once

$O(n \log n)$ because it splits and merges each level

$O(n^2)$ because it compares every pair of elements

Explanation

This question tests AP Computer Science A skills on recursive searching and sorting algorithms, focusing on analyzing the time complexity of merge sort. Recursion involves functions calling themselves with modified parameters until a base case is reached, effectively breaking down a problem into smaller, manageable parts. In this problem, merge sort divides the array in half at each level (creating log n levels) and performs O(n) work at each level to merge the subarrays. Choice C is correct because the algorithm has O(log n) recursive levels, and at each level, all n elements are processed during the merge operations, resulting in O(n log n) total time complexity. Choice D is incorrect because while there are O(log n) levels of recursion, it ignores the O(n) work done at each level for merging. To help students: Draw the recursion tree showing log n levels with n total elements processed at each level. Emphasize that time complexity analysis must consider both the depth of recursion and the work done at each level.

4

In this recursive merge sort on an int array, how does the algorithm handle the input array in recursive steps?


// Merge sort: split, sort halves recursively, then merge

public static void mergeSort(int[] nums, int left, int right) {

    // Base case: one element (already sorted)

    if (left >= right) {

        return;

    }

    int mid = (left + right) / 2;

    // Recursive calls: sort left half and right half

    mergeSort(nums, left, mid);

    mergeSort(nums, mid + 1, right);

    // Merge step: combine two sorted halves

    merge(nums, left, mid, right);

}

private static void merge(int[] nums, int left, int mid, int right) {

    int[] temp = new int<u>right - left + 1</u>;

    int i = left;

    int j = mid + 1;

    int k = 0;

    while (i <= mid && j <= right) {

        if (nums<u>i</u> <= nums<u>j</u>) temp<u>k++</u> = nums<u>i++</u>;

        else temp<u>k++</u> = nums<u>j++</u>;

    }

    while (i <= mid) temp<u>k++</u> = nums<u>i++</u>;

    while (j <= right) temp<u>k++</u> = nums<u>j++</u>;

    for (int t = 0; t < temp.length; t++) {

        nums<u>left + t</u> = temp<u>t</u>;

    }

}

It searches for the target value by halving the range

It chooses a pivot and partitions in place each call

It repeatedly splits into halves, then merges sorted subarrays

It swaps adjacent elements until the array is sorted

Explanation

This question tests AP Computer Science A skills on recursive searching and sorting algorithms, focusing on understanding how merge sort processes arrays recursively. Recursion involves functions calling themselves with modified parameters until a base case is reached, effectively breaking down a problem into smaller, manageable parts. In this problem, the merge sort algorithm divides the array into two halves at each recursive level, sorts each half independently through recursive calls, then merges the sorted halves back together. Choice B is correct because it accurately describes the divide-and-conquer approach: the array is repeatedly split into halves until single elements remain, then sorted subarrays are merged bottom-up. Choice A is incorrect because it describes bubble sort's behavior of swapping adjacent elements, not merge sort's divide-and-conquer strategy. To help students: Use visual diagrams showing the recursive tree structure of merge sort. Trace through a small array example showing how it splits down to single elements then merges back up in sorted order.

5

Given the recursive factorial method below, how does the recursive call in the code function to compute factorial(4)?


public class MathUtil {

    public static int factorial(int n) {

        if (n == 0) {

            return 1;

        }

        return n * factorial(n - 1);

    }

}

It multiplies n by factorial(n - 1) until reaching the base case.

It adds n to factorial(n - 1) until n becomes 0.

It returns 0 when n is 1, then multiplies back up.

It multiplies n by factorial(n + 1) until n becomes 4.

Explanation

This question tests AP Computer Science A skills on recursive searching and sorting algorithms, focusing on understanding how recursive factorial builds its result. Recursion involves functions calling themselves with modified parameters until a base case is reached, effectively breaking down a problem into smaller, manageable parts. In this problem, the factorial method demonstrates how factorial(4) computes 4! by multiplying 4 by factorial(3), which in turn multiplies 3 by factorial(2), and so on until reaching the base case. Choice B is correct because it accurately describes the recursive process: each call multiplies n by the factorial of (n-1), continuing until n reaches 0 (the base case), at which point the recursion unwinds and multiplications occur. Choice A is incorrect because it describes addition rather than multiplication; factorial uses the formula n! = n × (n-1)!, not n! = n + (n-1)!. To help students: Draw the call stack for factorial(4) showing how it builds up: 4×(3×(2×(1×(0!)))) = 4×(3×(2×(1×1))) = 24. Emphasize the multiplication operation and how results propagate back up the call stack.

6

What is the time complexity of this recursive binary search on a sorted integer array of size $n$?


public class Searcher {

    public static int binarySearch(int[] nums, int target, int low, int high) {

        if (low > high) {

            return -1;

        }

        int mid = (low + high) / 2;

        if (nums<u>mid</u> == target) {

            return mid;

        }

        if (target < nums<u>mid</u>) {

            return binarySearch(nums, target, low, mid - 1);

        } else {

            return binarySearch(nums, target, mid + 1, high);

        }

    }

}

$O(\log n)$ because each call halves the interval.

$O(n)$ because it may check every element.

$O(n \log n)$ because it divides and then merges.

$O(1)$ because it uses constant extra variables.

Explanation

This question tests AP Computer Science A skills on recursive searching and sorting algorithms, focusing on analyzing the time complexity of recursive binary search. Time complexity analysis requires understanding how the number of operations grows with input size n. In binary search, each recursive call eliminates half of the remaining elements by choosing to search either the left or right half based on the comparison with the middle element. Choice D is correct because the algorithm halves the search interval with each recursive call, resulting in at most log₂(n) recursive calls before the base case is reached, giving O(log n) time complexity. Choice A is incorrect because O(n) would mean checking every element, which contradicts binary search's divide-and-conquer approach that skips half the elements at each step. To help students: Draw recursion trees showing how the problem size decreases from n to n/2 to n/4, etc. Emphasize that the number of times you can divide n by 2 until reaching 1 is log₂(n), which is the maximum recursion depth.

7

In this recursive merge sort, how does the recursive call structure ensure the entire array becomes sorted?


public class Sorter {

    public static void mergeSort(int[] nums, int left, int right) {

        if (left >= right) {

            return;

        }

        int mid = (left + right) / 2;

        // Recursive calls sort subarrays

        mergeSort(nums, left, mid);

        mergeSort(nums, mid + 1, right);

        // Merge combines two sorted subarrays

        merge(nums, left, mid, right);

    }

    private static void merge(int[] nums, int left, int mid, int right) {

        int[] temp = new int<u>right - left + 1</u>;

        int i = left, j = mid + 1, k = 0;

        while (i <= mid && j <= right) {

            temp<u>k++</u> = (nums<u>i</u> <= nums<u>j</u>) ? nums<u>i++</u> : nums<u>j++</u>;

        }

        while (i <= mid) temp<u>k++</u> = nums<u>i++</u>;

        while (j <= right) temp<u>k++</u> = nums<u>j++</u>;

        for (int t = 0; t < temp.length; t++) nums<u>left + t</u> = temp<u>t</u>;

    }

}

Each call searches for the minimum element and swaps it into place.

Each call sorts both halves, then merge combines them into one sorted segment.

Each call reverses its segment, so merges become sorted automatically.

Each call sorts only the left half, and the right half stays unchanged.

Explanation

This question tests AP Computer Science A skills on recursive searching and sorting algorithms, focusing on understanding the divide-and-conquer strategy in merge sort. Merge sort works by recursively breaking down the problem into smaller subproblems until they're trivial to solve, then combining solutions. In this implementation, each call to mergeSort first recursively sorts the left half (left to mid), then the right half (mid+1 to right), and finally merges these two sorted halves into one sorted segment. Choice B is correct because it accurately describes the two-phase process: recursive calls sort both halves independently, then the merge function combines these sorted halves while maintaining order. Choice D is incorrect because merge sort must sort both halves, not just the left half, to ensure the entire array becomes sorted. To help students: Use tree diagrams to visualize the recursive decomposition and subsequent merging phases. Emphasize that the 'magic' happens in the merge step, which combines two sorted sequences into one larger sorted sequence.

8

How does this merge sort handle the input array in recursive steps before calling merge?


public class Sorter {

    // Sorts nums<u>left..right</u> by recursively sorting subranges

    public static void mergeSort(int[] nums, int left, int right) {

        if (left >= right) {

            return;

        }

        int mid = (left + right) / 2;

        // Recursive step: split into two index ranges

        mergeSort(nums, left, mid);

        mergeSort(nums, mid + 1, right);

        // Merge step combines sorted ranges

        merge(nums, left, mid, right);

    }

    private static void merge(int[] nums, int left, int mid, int right) {

        int[] temp = new int<u>right - left + 1</u>;

        int i = left, j = mid + 1, k = 0;

        while (i <= mid && j <= right) {

            temp<u>k++</u> = (nums<u>i</u> <= nums<u>j</u>) ? nums<u>i++</u> : nums<u>j++</u>;

        }

        while (i <= mid) temp<u>k++</u> = nums<u>i++</u>;

        while (j <= right) temp<u>k++</u> = nums<u>j++</u>;

        for (int t = 0; t < temp.length; t++) nums<u>left + t</u> = temp<u>t</u>;

    }

}

It removes elements from the array so recursion terminates sooner.

It uses the same mid value for all recursive calls.

It updates left/right to work on smaller index ranges.

It copies the entire array into two new arrays at each call.

Explanation

This question tests AP Computer Science A skills on recursive searching and sorting algorithms, focusing on how merge sort manages array segments during recursion. Efficient sorting algorithms minimize memory usage by working with index ranges rather than creating array copies. In this merge sort implementation, the original array is passed to all recursive calls, but each call operates on a specific segment defined by the left and right indices, effectively dividing the work without copying data. Choice B is correct because it accurately describes how the algorithm updates the left and right parameters to define progressively smaller index ranges, allowing each recursive call to focus on its assigned portion of the array. Choice A is incorrect because copying the entire array at each recursive call would be extremely inefficient and unnecessary when index boundaries suffice. To help students: Use diagrams showing the same array with different colored segments representing the ranges each recursive call handles. Emphasize that changing indices is much more efficient than copying array elements, especially for large datasets.

9

For this recursive merge sort, what is the base case that stops further splitting of the array?


public class Sorter {

    public static void mergeSort(int[] nums, int left, int right) {

        // Base case: one element (or empty) segment is already sorted

        if (left >= right) {

            return;

        }

        int mid = (left + right) / 2;

        // Recursive step: sort both halves

        mergeSort(nums, left, mid);

        mergeSort(nums, mid + 1, right);

        // Merge sorted halves

        merge(nums, left, mid, right);

    }

    private static void merge(int[] nums, int left, int mid, int right) {

        int[] temp = new int<u>right - left + 1</u>;

        int i = left;

        int j = mid + 1;

        int k = 0;

        // Merge elements in sorted order

        while (i <= mid && j <= right) {

            if (nums<u>i</u> <= nums<u>j</u>) {

                temp<u>k++</u> = nums<u>i++</u>;

            } else {

                temp<u>k++</u> = nums<u>j++</u>;

            }

        }

        while (i <= mid) {

            temp<u>k++</u> = nums<u>i++</u>;

        }

        while (j <= right) {

            temp<u>k++</u> = nums<u>j++</u>;

        }

        // Copy back

        for (int t = 0; t < temp.length; t++) {

            nums<u>left + t</u> = temp<u>t</u>;

        }

    }

}

When left >= right, return immediately.

When the array is in descending order, return immediately.

When left > right, return immediately.

When mid == 0, return immediately.

Explanation

This question tests AP Computer Science A skills on recursive searching and sorting algorithms, focusing on identifying the base case in recursive merge sort. The base case in merge sort represents when a segment is so small that it's already sorted by definition. In this implementation, the condition if (left >= right) serves as the base case, stopping recursion when the segment has one element (left == right) or is empty (left > right). Choice C is correct because when left >= right, the segment contains at most one element, which is inherently sorted and requires no further splitting or merging. Choice A is incorrect because it only covers the empty segment case (left > right) but misses the single-element case (left == right), which is also a valid base case. To help students: Explain that arrays of size 0 or 1 are sorted by definition. Trace through examples showing how recursive calls eventually reach segments where left equals right, representing single elements that form the building blocks for merging.

10

Given this recursive binary search, what is the base case that stops recursion when the target cannot be found?


public class Searcher {

    // Returns index of target in sorted array, or -1 if not found

    public static int binarySearch(int[] nums, int target, int low, int high) {

        // Base case: interval is empty

        if (low > high) {

            return -1;

        }

        int mid = (low + high) / 2;

        // Found target

        if (nums<u>mid</u> == target) {

            return mid;

        }

        // Recursive step: search one half

        if (target < nums<u>mid</u>) {

            return binarySearch(nums, target, low, mid - 1);

        } else {

            return binarySearch(nums, target, mid + 1, high);

        }

    }

}

When low == high, return -1.

When nums[mid] != target, return -1.

When mid == 0, return -1.

When low > high, return -1.

Explanation

This question tests AP Computer Science A skills on recursive searching and sorting algorithms, focusing on understanding the base case in recursive binary search. In recursive algorithms, the base case is the condition that stops the recursion and prevents infinite calls. In this binary search implementation, the base case if (low > high) occurs when the search interval becomes invalid (empty), meaning the target cannot be found in the remaining search space. Choice B is correct because when low > high, it indicates that the search boundaries have crossed, which happens after repeatedly narrowing the search interval without finding the target. Choice A is incorrect because low == high represents a valid single-element interval that still needs to be checked. To help students: Emphasize that base cases prevent infinite recursion and represent the simplest form of the problem. Practice tracing through examples where the target is not found, observing how the interval shrinks until low exceeds high.

Page 1 of 3