Code Templates
Use these adaptable code templates as starting points for solving divide and conquer problems. Each template includes the core structure with comments explaining the divide, conquer, and combine steps.
Merge Sort
Merge Sort is the classic example of Divide and Conquer. It guarantees $O(N \log N)$ time complexity and is a stable sort.
Time:
O(N log N)
O(N)
Code Breakdown
graph TD
Input[Input Array] -->|Divide| Left[Left Half]
Input -->|Divide| Right[Right Half]
Left -->|Recurse| SortedLeft[Sorted Left]
Right -->|Recurse| SortedRight[Sorted Right]
SortedLeft & SortedRight -->|Conquer: Merge| Output[Sorted Output]
/**
* Template for merge sort using divide and conquer
* Use when: Need stable sort, linked lists, external sorting
* Time: O(n log n), Space: O(n)
*/
function mergeSort(arr, left = 0, right = arr.length - 1) {
if (left >= right) return;
const mid = Math.floor((left + right) / 2);
// Divide: Sort both halves
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
// Conquer: Merge sorted halves
merge(arr, left, mid, right);
}
function merge(arr, left, mid, right) {
const n1 = mid - left + 1;
const n2 = right - mid;
// Create temporary arrays
const leftArr = new Array(n1);
const rightArr = new Array(n2);
// Copy data to temp arrays
for (let i = 0; i < n1; i++) leftArr[i] = arr[left + i];
for (let j = 0; j < n2; j++) rightArr[j] = arr[mid + 1 + j];
// Merge: Combine sorted arrays
let i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (leftArr[i] <= rightArr[j]) {
arr[k++] = leftArr[i++];
} else {
arr[k++] = rightArr[j++];
}
}
// Copy remaining elements
while (i < n1) arr[k++] = leftArr[i++];
while (j < n2) arr[k++] = rightArr[j++];
}"""
Template for merge sort using divide and conquer
Use when: Need stable sort, linked lists, external sorting
Time: O(n log n), Space: O(n)
"""
def merge_sort(arr, left=None, right=None):
if left is None:
left = 0
if right is None:
right = len(arr) - 1
if left >= right:
return
mid = (left + right) // 2
# Divide: Sort both halves
merge_sort(arr, left, mid)
merge_sort(arr, mid + 1, right)
# Conquer: Merge sorted halves
merge(arr, left, mid, right)
def merge(arr, left, mid, right):
n1 = mid - left + 1
n2 = right - mid
# Create temporary arrays
left_arr = arr[left:left + n1]
right_arr = arr[mid + 1:mid + 1 + n2]
# Merge: Combine sorted arrays
i = j = 0
k = left
while i < n1 and j < n2:
if left_arr[i] <= right_arr[j]:
arr[k] = left_arr[i]
i += 1
else:
arr[k] = right_arr[j]
j += 1
k += 1
# Copy remaining elements
while i < n1:
arr[k] = left_arr[i]
i += 1
k += 1
while j < n2:
arr[k] = right_arr[j]
j += 1
k += 1/**
* Template for merge sort using divide and conquer
* Use when: Need stable sort, linked lists, external sorting
* Time: O(n log n), Space: O(n)
*/
public class MergeSort {
public void mergeSort(int[] arr, int left, int right) {
if (left >= right) return;
int mid = left + (right - left) / 2;
// Divide: Sort both halves
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
// Conquer: Merge sorted halves
merge(arr, left, mid, right);
}
private void merge(int[] arr, int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
// Create temporary arrays
int[] leftArr = new int[n1];
int[] rightArr = new int[n2];
// Copy data to temp arrays
for (int i = 0; i < n1; i++) leftArr[i] = arr[left + i];
for (int j = 0; j < n2; j++) rightArr[j] = arr[mid + 1 + j];
// Merge: Combine sorted arrays
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (leftArr[i] <= rightArr[j]) {
arr[k++] = leftArr[i++];
} else {
arr[k++] = rightArr[j++];
}
}
// Copy remaining elements
while (i < n1) arr[k++] = leftArr[i++];
while (j < n2) arr[k++] = rightArr[j++];
}
}/**
* Template for merge sort using divide and conquer
* Use when: Need stable sort, linked lists, external sorting
* Time: O(n log n), Space: O(n)
*/
#include <vector>
using namespace std;
class MergeSort {
public:
void mergeSort(vector<int>& arr, int left, int right) {
if (left >= right) return;
int mid = left + (right - left) / 2;
// Divide: Sort both halves
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
// Conquer: Merge sorted halves
merge(arr, left, mid, right);
}
private:
void merge(vector<int>& arr, int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
// Create temporary vectors
vector<int> leftArr(n1), rightArr(n2);
// Copy data to temp vectors
for (int i = 0; i < n1; i++) leftArr[i] = arr[left + i];
for (int j = 0; j < n2; j++) rightArr[j] = arr[mid + 1 + j];
// Merge: Combine sorted arrays
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (leftArr[i] <= rightArr[j]) {
arr[k++] = leftArr[i++];
} else {
arr[k++] = rightArr[j++];
}
}
// Copy remaining elements
while (i < n1) arr[k++] = leftArr[i++];
while (j < n2) arr[k++] = rightArr[j++];
}
};/**
* Template for merge sort using divide and conquer
* Use when: Need stable sort, linked lists, external sorting
* Time: O(n log n), Space: O(n)
*/
func mergeSort(arr []int, left int, right int) {
if left >= right {
return
}
mid := left + (right-left)/2
// Divide: Sort both halves
mergeSort(arr, left, mid)
mergeSort(arr, mid+1, right)
// Conquer: Merge sorted halves
merge(arr, left, mid, right)
}
func merge(arr []int, left int, mid int, right int) {
n1 := mid - left + 1
n2 := right - mid
// Create temporary slices
leftArr := make([]int, n1)
rightArr := make([]int, n2)
// Copy data to temp slices
for i := 0; i < n1; i++ {
leftArr[i] = arr[left+i]
}
for j := 0; j < n2; j++ {
rightArr[j] = arr[mid+1+j]
}
// Merge: Combine sorted arrays
i, j, k := 0, 0, left
for i < n1 && j < n2 {
if leftArr[i] <= rightArr[j] {
arr[k] = leftArr[i]
i++
} else {
arr[k] = rightArr[j]
j++
}
k++
}
// Copy remaining elements
for i < n1 {
arr[k] = leftArr[i]
i++
k++
}
for j < n2 {
arr[k] = rightArr[j]
j++
k++
}
}# Template for merge sort using divide and conquer
# Use when: Need stable sort, linked lists, external sorting
# Time: O(n log n), Space: O(n)
def merge_sort(arr, left = 0, right = arr.length - 1)
return if left >= right
mid = (left + right) / 2
# Divide: Sort both halves
merge_sort(arr, left, mid)
merge_sort(arr, mid + 1, right)
# Conquer: Merge sorted halves
merge(arr, left, mid, right)
end
def merge(arr, left, mid, right)
left_arr = arr[left..mid]
right_arr = arr[mid+1..right]
i = 0
j = 0
k = left
# Merge: Combine sorted arrays
while i < left_arr.length && j < right_arr.length
if left_arr[i] <= right_arr[j]
arr[k] = left_arr[i]
i += 1
else
arr[k] = right_arr[j]
j += 1
end
k += 1
end
# Copy remaining elements
while i < left_arr.length
arr[k] = left_arr[i]
i += 1
k += 1
end
while j < right_arr.length
arr[k] = right_arr[j]
j += 1
k += 1
end
endQuick Sort
Quick Sort is an in-place sorting algorithm that is often faster than Merge Sort in practice, though its worst-case complexity is $O(N^2)$.
Time:
O(N log N)
O(log N)
Code Breakdown
graph TD
Input[Array] -->|Partition| P[Partition around Pivot]
P -->|Divide| Left[Elements < Pivot]
P -->|Divide| Right[Elements > Pivot]
Left -->|Recurse Sort| SortedLeft
Right -->|Recurse Sort| SortedRight
/**
* Template for quick sort using divide and conquer
* Use when: Need in-place sorting, average O(n log n)
* Time: O(n log n) avg, O(n^2) worst, Space: O(log n)
*/
function quickSort(arr, low = 0, high = arr.length - 1) {
if (low < high) {
// Partition the array
const pivotIndex = partition(arr, low, high);
// Conquer: Recursively sort subarrays
quickSort(arr, low, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, high);
}
}
function partition(arr, low, high) {
const pivot = arr[high]; // Choose rightmost element as pivot
let i = low - 1;
for (let j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
[arr[i], arr[j]] = [arr[j], arr[i]]; // Swap
}
}
[arr[i + 1], arr[high]] = [arr[high], arr[i + 1]]; // Place pivot
return i + 1;
}"""
Template for quick sort using divide and conquer
Use when: Need in-place sorting, average O(n log n)
Time: O(n log n) avg, O(n^2) worst, Space: O(log n)
"""
def quick_sort(arr, low=None, high=None):
if low is None:
low = 0
if high is None:
high = len(arr) - 1
if low < high:
# Partition the array
pivot_index = partition(arr, low, high)
# Conquer: Recursively sort subarrays
quick_sort(arr, low, pivot_index - 1)
quick_sort(arr, pivot_index + 1, high)
def partition(arr, low, high):
pivot = arr[high] # Choose rightmost element as pivot
i = low - 1
for j in range(low, high):
if arr[j] < pivot:
i += 1
arr[i], arr[j] = arr[j], arr[i] # Swap
arr[i + 1], arr[high] = arr[high], arr[i + 1] # Place pivot
return i + 1/**
* Template for quick sort using divide and conquer
* Use when: Need in-place sorting, average O(n log n)
* Time: O(n log n) avg, O(n^2) worst, Space: O(log n)
*/
public class QuickSort {
public void quickSort(int[] arr, int low, int high) {
if (low < high) {
// Partition the array
int pivotIndex = partition(arr, low, high);
// Conquer: Recursively sort subarrays
quickSort(arr, low, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, high);
}
}
private int partition(int[] arr, int low, int high) {
int pivot = arr[high]; // Choose rightmost element as pivot
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
// Swap arr[i] and arr[j]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// Swap arr[i+1] and arr[high] (or pivot)
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return i + 1;
}
}/**
* Template for quick sort using divide and conquer
* Use when: Need in-place sorting, average O(n log n)
* Time: O(n log n) avg, O(n^2) worst, Space: O(log n)
*/
class QuickSort {
public:
void quickSort(vector<int>& arr, int low, int high) {
if (low < high) {
// Partition the array
int pivotIndex = partition(arr, low, high);
// Conquer: Recursively sort subarrays
quickSort(arr, low, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, high);
}
}
private:
int partition(vector<int>& arr, int low, int high) {
int pivot = arr[high]; // Choose rightmost element as pivot
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]); // Place pivot
return i + 1;
}
};/**
* Template for quick sort using divide and conquer
* Use when: Need in-place sorting, average O(n log n)
* Time: O(n log n) avg, O(n^2) worst, Space: O(log n)
*/
func quickSort(arr []int, low int, high int) {
if low < high {
// Partition the array
pivotIndex := partition(arr, low, high)
// Conquer: Recursively sort subarrays
quickSort(arr, low, pivotIndex-1)
quickSort(arr, pivotIndex+1, high)
}
}
func partition(arr []int, low int, high int) int {
pivot := arr[high] // Choose rightmost element as pivot
i := low - 1
for j := low; j < high; j++ {
if arr[j] < pivot {
i++
arr[i], arr[j] = arr[j], arr[i]
}
}
arr[i+1], arr[high] = arr[high], arr[i+1]
return i + 1
}# Template for quick sort using divide and conquer
# Use when: Need in-place sorting, average O(n log n)
# Time: O(n log n) avg, O(n^2) worst, Space: O(log n)
def quick_sort(arr, low = 0, high = arr.length - 1)
if low < high
# Partition the array
pivot_index = partition(arr, low, high)
# Conquer: Recursively sort subarrays
quick_sort(arr, low, pivot_index - 1)
quick_sort(arr, pivot_index + 1, high)
end
end
def partition(arr, low, high)
pivot = arr[high] # Choose rightmost element as pivot
i = low - 1
(low...high).each do |j|
if arr[j] < pivot
i += 1
arr[i], arr[j] = arr[j], arr[i] # Swap
end
end
arr[i + 1], arr[high] = arr[high], arr[i + 1] # Place pivot
i + 1
endBinary Search
Binary Search is the simplest form of Divide and Conquer, where we discard half the problem space at each step.
Time:
O(log N)
O(1)
Code Breakdown
graph TD
Start[Search Range] --> Check{Middle == Target?}
Check -->|Yes| Found[Return Index]
Check -->|No| Compare{Middle > Target?}
Compare -->|Yes| Left[Search Left Half]
Compare -->|No| Right[Search Right Half]
Left --> Start
Right --> Start
/**
* Template for binary search
* Use when: Searching in sorted arrays
* Time: O(log n), Space: O(1) iterative
*/
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}"""
Template for binary search
Use when: Searching in sorted arrays
Time: O(log n), Space: O(1) iterative
"""
def binary_search(arr, target):
left = 0
right = len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1/**
* Template for binary search
* Use when: Searching in sorted arrays
* Time: O(log n), Space: O(1) iterative
*/
public class BinarySearch {
public int binarySearch(int[] arr, int target) {
int left = 0;
int right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
}/**
* Template for binary search
* Use when: Searching in sorted arrays
* Time: O(log n), Space: O(1) iterative
*/
class BinarySearch {
public:
int binarySearch(vector<int>& arr, int target) {
int left = 0;
int right = arr.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
};/**
* Template for binary search
* Use when: Searching in sorted arrays
* Time: O(log n), Space: O(1) iterative
*/
func binarySearch(arr []int, target int) int {
left, right := 0, len(arr)-1
for left <= right {
mid := left + (right-left)/2
if arr[mid] == target {
return mid
} else if arr[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}
return -1
}# Template for binary search
# Use when: Searching in sorted arrays
# Time: O(log n), Space: O(1) iterative
def binary_search(arr, target)
left = 0
right = arr.length - 1
while left <= right
mid = (left + right) / 2
if arr[mid] == target
return mid
elsif arr[mid] < target
left = mid + 1
else
right = mid - 1
end
end
-1
endPractice
Link your understanding to practice with the Problems page.