Divide and Conquer breaks a problem into smaller parts, solves each part, and combines results. What is the main advantage of this approach?
Think about how breaking a big task into smaller tasks helps.
Divide and Conquer reduces problem size step-by-step, simplifying complex problems. It does not always use less memory or guarantee fastest solutions for all problems. Combining results is essential.
What is the printed output after running this merge sort code on the list [4, 1, 3]?
def merge_sort(arr): if len(arr) <= 1: return arr mid = len(arr) // 2 left = merge_sort(arr[:mid]) right = merge_sort(arr[mid:]) print(f"Left: {left}, Right: {right}") return merge(left, right) def merge(left, right): result = [] i = j = 0 while i < len(left) and j < len(right): if left[i] < right[j]: result.append(left[i]) i += 1 else: result.append(right[j]) j += 1 result.extend(left[i:]) result.extend(right[j:]) return result merge_sort([4, 1, 3])
Trace the recursive calls and see how the list splits.
The list splits into [4] and [1, 3], then [1, 3] splits into [1] and [3]. These are the printed left and right parts.
Consider this code that tries to find the maximum in a list using Divide and Conquer. Why does it cause infinite recursion?
def find_max(arr): if len(arr) == 1: return arr[0] mid = len(arr) // 2 left_max = find_max(arr[:mid]) right_max = find_max(arr[mid:]) return max(left_max, right_max) print(find_max([]))
What happens when the input list is empty?
The function does not check for empty lists before slicing. When arr is empty, it keeps calling itself with empty lists, causing infinite recursion.
Binary Search uses Divide and Conquer. How does this approach improve searching in a sorted list?
Think about how cutting the list in half helps find the target faster.
Binary Search divides the list into halves, discarding half each time, making search time much faster than checking every element.
What is the output of the partition function calls when quicksorting the list [3, 6, 2, 7]?
def partition(arr, low, high): pivot = arr[high] i = low - 1 for j in range(low, high): if arr[j] <= pivot: i += 1 arr[i], arr[j] = arr[j], arr[i] arr[i+1], arr[high] = arr[high], arr[i+1] print(f"Partitioned: {arr[low:high+1]}") return i + 1 def quicksort(arr, low, high): if low < high: pi = partition(arr, low, high) quicksort(arr, low, pi - 1) quicksort(arr, pi + 1, high) arr = [3, 6, 2, 7] quicksort(arr, 0, len(arr) - 1)
Trace the partition steps and how the pivot moves.
The first partition on [3, 6, 2, 7] (pivot 7) prints [3, 6, 2, 7]. Then left subarray [3, 6, 2] (pivot 2) becomes [2, 6, 3] and prints it. Then sub-right [6, 3] (pivot 3) becomes [3, 6] and prints [3, 6].
