DEV Community

Cover image for Divide and Conquer: A powerful strategy for solving problems
Anurag Verma
Anurag Verma

Posted on • Edited on

Divide and Conquer: A powerful strategy for solving problems

Divide and conquer is a general algorithmic strategy that involves dividing a problem into smaller subproblems, solving the subproblems, and then combining the solutions to the subproblems to solve the original problem. This strategy is often used to solve problems that are too large or complex to be solved directly.

One of the key benefits of divide and conquer is that it can lead to highly efficient algorithms, as it allows you to take advantage of the fact that smaller problems are often easier to solve than larger ones. By breaking a problem down into smaller pieces, you can often solve it more quickly than you could by attempting to solve it all at once.

Divide and conquer algorithms are often implemented using recursive functions, which divide the problem into smaller subproblems and then call themselves with the subproblems as arguments. This allows the algorithm to keep dividing the problem until it reaches a small enough size that it can be solved directly.

Some common examples of divide and conquer algorithms include:

  • Merge sort: A sorting algorithm that divides an array into smaller subarrays, sorts the subarrays, and then merges them back together to form a sorted array.

  • Quick sort: Another sorting algorithm that uses divide and conquer to sort an array by selecting a "pivot" element and partitioning the array around it.

  • Binary search: An algorithm that searches for a specific element in a sorted array by dividing the array in half and searching only in the half that is likely to contain the element.

  • Karatsuba multiplication: An algorithm for multiplying large numbers that divides the numbers into smaller pieces and then uses recursive calls to multiply the pieces and combine the results.

Here is an example of a problem that can be solved using divide and conquer:

Suppose you are given an array of integers and you want to find the maximum sum of any contiguous subarray of the array. One way to solve this problem is to use a divide and conquer approach.

The first step is to divide the array into two smaller subarrays. You can do this by finding the midpoint of the array and splitting it into two halves.

Next, you can solve the problem for each of the two subarrays by finding the maximum sum of a contiguous subarray in each of them. To do this, you can use the same divide and conquer approach, dividing each subarray into smaller subarrays and continuing until you reach a subarray of size 1.

Finally, you can combine the solutions to the subproblems to solve the original problem. In this case, you can do this by considering three different cases:

  1. The maximum sum of a contiguous subarray includes the element at the midpoint of the array. In this case, you need to find the maximum sum of a contiguous subarray that includes both the element at the midpoint and some elements from one of the two subarrays.

  2. The maximum sum of a contiguous subarray lies entirely within one of the two subarrays. In this case, the solution is simply the maximum sum of a contiguous subarray that you found for that subarray.

  3. The maximum sum of a contiguous subarray lies entirely within the other subarray. In this case, the solution is simply the maximum sum of a contiguous subarray that you found for the other subarray.

By combining the solutions to the subproblems in this way, you can find the maximum sum of a contiguous subarray for the entire array.

Here is a Python function that uses divide and conquer to find the maximum sum of a contiguous subarray of an array:

def maximum_subarray_sum(arr, start, end):
  # base case: if the array has only one element, the maximum sum is the element itself
  if start == end:
    return arr[start]

  # divide the array into two subarrays
  mid = (start + end) // 2

  # find the maximum sum of a contiguous subarray in the left subarray
  left_sum = maximum_subarray_sum(arr, start, mid)

  # find the maximum sum of a contiguous subarray in the right subarray
  right_sum = maximum_subarray_sum(arr, mid + 1, end)

  # find the maximum sum of a contiguous subarray that includes the element at the midpoint of the array
  cross_sum = find_maximum_crossing_subarray(arr, start, mid, end)

  # return the maximum of the three sums
  return max(left_sum, right_sum, cross_sum)

def find_maximum_crossing_subarray(arr, start, mid, end):
  # find the maximum sum of a contiguous subarray that includes the element at the midpoint of the array
  # and some elements from the left subarray
  left_sum = float('-inf')
  current_sum = 0
  for i in range(mid, start - 1, -1):
    current_sum += arr[i]
    left_sum = max(left_sum, current_sum)

  # find the maximum sum of a contiguous subarray that includes the element at the midpoint of the array
  # and some elements from the right subarray
  right_sum = float('-inf')
  current_sum = 0
  for i in range(mid + 1, end + 1):
    current_sum += arr[i]
    right_sum = max(right_sum, current_sum)

  # return the sum of the two subarrays
  return left_sum + right_sum
Enter fullscreen mode Exit fullscreen mode

To use this function, you can simply call maximum_subarray_sum(arr, 0, len(arr) - 1), where arr is the array of integers that you want to find the maximum sum of a contiguous subarray for. The function will return the maximum sum of a contiguous subarray of the array.

Below is the explanation of the above code:

maximum_subarray_sum(arr, start, end) is a recursive function that uses divide and conquer to find the maximum sum of a contiguous subarray of the array arr from index start to index end. The function works as follows:

  1. If the array has only one element (i.e., start and end are both equal to the same index), the maximum sum is the element itself, so the function returns the element.

  2. If the array has more than one element, the function divides the array into two subarrays by finding the midpoint mid of the array and setting mid to be the end of the left subarray and the start of the right subarray.

  3. The function then calls itself with the left subarray as its argument and assigns the result to left_sum. This will find the maximum sum of a contiguous subarray in the left subarray.

  4. The function then calls itself with the right subarray as its argument and assigns the result to right_sum. This will find the maximum sum of a contiguous subarray in the right subarray.

  5. The function then calls the helper function find_maximum_crossing_subarray(arr, start, mid, end) to find the maximum sum of a contiguous subarray that includes the element at the midpoint of the array and some elements from both the left and right subarrays. This value is assigned to cross_sum.

  6. Finally, the function returns the maximum of the three sums left_sum, right_sum, and cross_sum, which will be the maximum sum of a contiguous subarray of the entire array.

find_maximum_crossing_subarray(arr, start, mid, end) is a helper function that finds the maximum sum of a contiguous subarray of the array arr from index start to index end that includes the element at index mid (which is the midpoint of the array). The function works as follows:

  1. The function initializes the variable left_sum to be the smallest possible value and the variable current_sum to be 0. It then iterates over the elements of the left subarray (from index mid down to index start) and adds each element to current_sum. It then updates left_sum to be the maximum of left_sum and current_sum. This will find the maximum sum of a contiguous subarray that includes the element at the midpoint of the array and some elements from the left subarray.

  2. The function initializes the variable right_sum to be the smallest possible value and the variable current_sum to be 0. It then iterates over the elements of the right subarray (from index mid + 1 up to index end) and adds each element to current_sum. It then updates right_sum to be the maximum of right_sum and current_sum. This will find the maximum sum of a contiguous subarray that includes the element at the midpoint of the array and some elements from the right subarray.

  3. Finally, the function returns the sum of left_sum and right_sum, which will be the maximum sum of a contiguous subarray that includes the element at the midpoint of the array and some elements from both the left and right subarrays. This value can be used by the maximum_subarray_sum function to find the maximum sum of a contiguous subarray of the entire array.

There are some common patterns of problems that are often solved using divide and conquer. Some examples include:

  1. Searching and sorting: As mentioned earlier, algorithms such as merge sort and binary search use divide and conquer to efficiently search for and sort elements.

  2. Optimization problems: Many optimization problems can be solved using divide and conquer, as the strategy allows you to break the problem down into smaller subproblems and find the optimal solution for each subproblem. Examples include finding the maximum sum of a contiguous subarray (as mentioned earlier) and finding the shortest path between two points in a graph.

  3. Problems with overlapping subproblems: Some problems involve computing the same subproblems multiple times, which can be inefficient. Divide and conquer algorithms can be used to store the results of each subproblem and reuse them when needed, which can improve the efficiency of the algorithm. Examples include the Fibonacci sequence and the shortest path between two points in a graph.

  4. Problems with a recursive structure: Some problems have a recursive structure that can be exploited using divide and conquer. For example, the problem of computing the nth term of the Fibonacci sequence can be solved using recursive calls to compute the previous two terms.

I hope this helps! Let me know if you have any other questions about divide and conquer algorithms.

Buy Me A Coffee

Top comments (0)