Divide and Conquer: A powerful strategy for solving problems
Anurag Verma
Posted on December 30, 2022
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:
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.
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.
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
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:
If the array has only one element (i.e.,
start
andend
are both equal to the same index), the maximum sum is the element itself, so the function returns the element.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 settingmid
to be the end of the left subarray and the start of the right subarray.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.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.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 tocross_sum
.Finally, the function returns the maximum of the three sums
left_sum
,right_sum
, andcross_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:
The function initializes the variable
left_sum
to be the smallest possible value and the variablecurrent_sum
to be 0. It then iterates over the elements of the left subarray (from indexmid
down to indexstart
) and adds each element tocurrent_sum
. It then updatesleft_sum
to be the maximum ofleft_sum
andcurrent_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.The function initializes the variable
right_sum
to be the smallest possible value and the variablecurrent_sum
to be 0. It then iterates over the elements of the right subarray (from indexmid + 1
up to indexend
) and adds each element tocurrent_sum
. It then updatesright_sum
to be the maximum ofright_sum
andcurrent_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.Finally, the function returns the sum of
left_sum
andright_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 themaximum_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:
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.
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.
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.
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.
Posted on December 30, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.