One of the most famous hard problems on LeetCode is Median of Two Sorted Arrays. At first glance, it looks straightforward—you just need the median of two sorted arrays. But the catch is that the required time complexity is O(log(m + n)), which rules out the obvious approach.
Let’s walk through both the simple solution and the optimal binary search approach.
Problem Statement
Given two sorted integer arrays nums1 and nums2 of sizes m and n, return the median of all elements.
The required time complexity is:
O(log(m + n))
Example 1
Input:
nums1 = [1,2]
nums2 = [3]
Output:
2.0Merged array:
[1,2,3]Median = 2
Example 2
Input:
nums1 = [1,3]
nums2 = [2,4]
Output:
2.5Merged array:
[1,2,3,4]Median = (2 + 3) / 2 = 2.5
Solution 1: Merge and Sort (Brute Force)
The simplest idea is to combine both arrays, sort them, and then calculate the median.
from typing import List
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
merged = nums1 + nums2
merged.sort()
length = len(merged)
if length % 2 == 0:
return (merged[length // 2 - 1] + merged[length // 2]) / 2
else:
return merged[length // 2]How it works
- Merge both arrays.
- Sort the merged array.
- If the total length is odd, return the middle element.
- If even, return the average of the two middle elements.
Time Complexity
- Merging: O(m + n)
- Sorting: O((m+n) log(m+n))
Overall:
O((m+n) log(m+n))Space Complexity
O(m+n)Although this solution is easy to understand, it doesn’t satisfy the problem’s required complexity.
Solution 2: Binary Search (Optimal)
To achieve O(log(min(m, n))), we use binary search on the smaller array.
Instead of merging arrays, we partition both arrays so that:
- Every element on the left partition is less than or equal to every element on the right partition.
- The left partition contains exactly half of the total elements.
This allows us to directly compute the median.
Step 1: Always Binary Search the Smaller Array
if len(nums1) > len(nums2):
nums1, nums2 = nums2, nums1Searching the smaller array guarantees logarithmic complexity.
Step 2: Calculate the Partition
Suppose
m = len(nums1)
n = len(nums2)Total elements:
total = m + n
half = (total + 1) // 2During binary search:
i = (l + r) // 2
j = half - iHere,
i= partition index innums1j= partition index innums2
Step 3: Get Partition Values
For every partition, we define four values.
In code:
nums1left = float("-inf") if i == 0 else nums1[i-1]
nums1right = float("inf") if i == m else nums1[i]
nums2left = float("-inf") if j == 0 else nums2[j-1]
nums2right = float("inf") if j == n else nums2[j]Using -inf and inf handles edge cases where the partition is at the beginning or end of an array.
Step 4: Check if the Partition is Correct
The correct partition satisfies:
nums1left <= nums2right
and
nums2left <= nums1rightThis means:
- Every value on the left is less than or equal to every value on the right.
Step 5: Calculate the Median
Odd Total Length
Return the maximum value from the left partition.
max(nums1left, nums2left)Even Total Length
Return the average of:
- Largest value on the left
- Smallest value on the right
(max(nums1left, nums2left) + min(nums1right, nums2right)) / 2Step 6: Adjust Binary Search
If
nums1left > nums2rightthen we moved too far right in nums1.
Move left.
r = i - 1Otherwise,
l = i + 1Move right.
Complete Optimal Solution
from typing import List
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
if len(nums1) > len(nums2):
nums1, nums2 = nums2, nums1
m, n = len(nums1), len(nums2)
total = m + n
half = (total + 1) // 2
l, r = 0, m
while l <= r:
i = (l + r) // 2
j = half - i
nums1left = float("-inf") if i == 0 else nums1[i-1]
nums1right = float("inf") if i == m else nums1[i]
nums2left = float("-inf") if j == 0 else nums2[j-1]
nums2right = float("inf") if j == n else nums2[j]
if nums1left <= nums2right and nums2left <= nums1right:
if total % 2:
return max(nums1left, nums2left)
return (
max(nums1left, nums2left)
+ min(nums1right, nums2right)
) / 2
if nums1left > nums2right:
r = i - 1
else:
l = i + 1Dry Run
Consider:
nums1 = [1,3]
nums2 = [2,4]Total elements = 4
Half = 2
First partition:
nums1
1 | 3
nums2
2 | 4Left values:
1
2Right values:
3
4Conditions:
1 <= 4 ✓
2 <= 3 ✓Valid partition.
Median:
(max(1,2) + min(3,4)) / 2
= (2 + 3) / 2
= 2.5Complexity Analysis
Brute Force
Metric | Complexity |
|---|---|
Time | O((m+n) log(m+n)) |
Space | O(m+n) |
Binary Search
Metric | Complexity |
|---|---|
Time | O(log(min(m,n))) |
Space | O(1) |
Key Takeaways
- The merge-and-sort solution is intuitive but does not meet the required time complexity.
- The optimal solution avoids merging entirely by using binary search on the smaller array.
- The core idea is to find a partition where every element on the left is less than or equal to every element on the right.
- Once the correct partition is found, the median can be computed in constant time.
This problem is considered one of the best exercises for mastering binary search on partitions. While the logic may seem intimidating at first, understanding the partition conditions makes the solution much easier to reason about.