The divide-and-conquer strategy breaks a complex problem into smaller subproblems of the same type, solves them recursively, and then combines their results to construct the final solution. Merge Sort is a classic manifestation of this technique: it splits an array down the middle, recursively sorts both halves, and merges them back together in linear time.
Because merging always processes elements sequentially, Merge Sort maintains structural stability and guarantees an optimal $O(n \log n)$ time complexity across worst, average, and best-case scenarios, at the cost of $O(n)$ extra auxiliary memory space.
2. Quick Sort & Partitioning Strategies
Unlike Merge Sort, Quick Sort is an in-place sorting algorithm that partitions an array around a chosen pivot element. Elements smaller than the pivot are moved to its left, and larger elements are moved to its right. The subarrays are then sorted recursively.
Worst-Case Handling: While Quick Sort runs in $O(n \log n)$ on average, poorly chosen pivots (such as always picking the first or last element on already sorted data) can degrade performance to $O(n^2)$. This is mitigated in production environments using randomized pivot selection or the median-of-three technique.
// C++ Solution: Merge Sort Implementation
#include <vector>
class Solution {
public:
std::vector<int> sortArray(std::vector<int>& nums) {
if (nums.size() <= 1) return nums;
int mid = nums.size() / 2;
std::vector<int> left(nums.begin(), nums.begin() + mid);
std::vector<int> right(nums.begin() + mid, nums.end());
left = sortArray(left);
right = sortArray(right);
return merge(left, right);
}
private:
std::vector<int> merge(const std::vector<int>& left, const std::vector<int>& right) {
std::vector<int> res;
int i = 0, j = 0;
while (i < left.size() && j < right.size()) {
if (left[i] <= right[j]) res.push_back(left[i++]);
else res.push_back(right[j++]);
}
while (i < left.size()) res.push_back(left[i++]);
while (j < right.size()) res.push_back(right[j++]);
return res;
}
};
# Python Solution: Merge Sort Implementationclass Solution:
defsortArray(self, nums: list[int]) -> list[int]:
iflen(nums) <= 1:
return nums
mid = len(nums) // 2
left = self.sortArray(nums[:mid])
right = self.sortArray(nums[mid:])
return self.merge(left, right)
defmerge(self, left: list[int], right: list[int]) -> list[int]:
res = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
res.append(left[i])
i += 1
else:
res.append(right[j])
j += 1
res.extend(left[i:])
res.extend(right[j:])
return res
// Java Solution: Merge Sort Implementationimport java.util.Arrays;
class Solution {
publicint[] sortArray(int[] nums) {
if (nums.length <= 1) return nums;
int mid = nums.length / 2;
int[] left = sortArray(Arrays.copyOfRange(nums, 0, mid));
int[] right = sortArray(Arrays.copyOfRange(nums, mid, nums.length));
return merge(left, right);
}
privateint[] merge(int[] left, int[] right) {
int[] res = newint[left.length + right.length];
int i = 0, j = 0, k = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) res[k++] = left[i++];
else res[k++] = right[j++];
}
while (i < left.length) res[k++] = left[i++];
while (j < right.length) res[k++] = right[j++];
return res;
}
}
3. Homework & Quiz Overview
To lock in your mastery, complete the implementation exercises for both Merge Sort and Quick Sort, and tackle the Count Inversions problem using modified merge mechanics.
Quick Check: Test Your Intuition
What is the key structural and space difference between Merge Sort and Quick Sort?