The Divide-and-Conquer (D&C) approach is a fundamental algorithm design paradigm where a problem is broken down into smaller subproblems, solved independently, and then combined to produce the solution to the original problem. This technique is especially useful for problems that can be recursively divided into smaller subproblems, which can be solved more easily and then combined.
Divide-and-conquer is commonly used in many well-known algorithms like Merge Sort, Quick Sort, and Binary Search.
Merge Sort is a classic example of the divide-and-conquer paradigm. The algorithm divides an array into two halves, recursively sorts each half, and then merges the sorted halves to get the final sorted array.
Steps:
def merge_sort(arr):
if len(arr) <= 1:
return arr
# Divide: Find the middle point and divide the array into two halves
mid = len(arr) // 2
left = merge_sort(arr[:mid]) # Recursively sort the left half
right = merge_sort(arr[mid:]) # Recursively sort the right half
# Combine: Merge the sorted halves
return merge(left, right)
def merge(left, right):
sorted_arr = []
i = j = 0
# Merge two sorted arrays
while i < len(left) and j < len(right):
if left[i] < right[j]:
sorted_arr.append(left[i])
i += 1
else:
sorted_arr.append(right[j])
j += 1
# Append remaining elements (if any)
sorted_arr.extend(left[i:])
sorted_arr.extend(right[j:])
return sorted_arr
Time Complexity:
So, the overall time complexity of Merge Sort is O(n log n).
Quick Sort is another well-known algorithm that uses the divide-and-conquer strategy. It picks a pivot element from the array, partitions the array into two subarrays (those smaller and greater than the pivot), and then recursively sorts the subarrays.
Steps:
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2] # Choose the middle element as pivot
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
# Recursively sort the left and right subarrays
return quick_sort(left) + middle + quick_sort(right)
Time Complexity:
Binary Search is a simple and efficient divide-and-conquer algorithm used to search for an element in a sorted array. The algorithm works by repeatedly dividing the search interval in half.
Steps:
def binary_search(arr, target):
low, high = 0, len(arr) - 1
while low <= high:
mid = (low + high) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1 # Target not found
Time Complexity:
Strassen's Matrix Multiplication is a divide-and-conquer algorithm for matrix multiplication that reduces the number of multiplications required.
Instead of performing standard matrix multiplication, Strassen divides each matrix into smaller submatrices, recursively multiplies them, and combines the results.
Steps:
Time Complexity:
The Divide-and-Conquer approach is a powerful technique used to solve problems by recursively breaking them into smaller, more manageable subproblems, solving each subproblem, and then combining the results. This technique is widely used in algorithms like Merge Sort, Quick Sort, and Binary Search. While it often results in efficient solutions, it can also introduce recursive overhead and complexity in some cases. Divide-and-conquer is particularly useful when the problem can be broken down into independent subproblems, and the subproblems are easier to solve than the original problem.
Open this section to load past papers