Median of Two Sorted Arrays
The problem statement may be found on leetcode.
Analysis of the Problem
The basics of the algorithm are actually very straightforward - it is the edge cases and implementation that made this quite tricky. Given the finite subsets \(\{a_j\}\) and \(\{b_k\}\) of \(\mathbb{N}\) indexed in monotonic order, the algorithm is
Take \(j_{start} = max(j)\) and \(j_{stop} = min(j)\), and likewise for \(k_{start}\) and \(k_{stop}\).
If \(j_{start} <= j_{stop}\) and \(k_{start} <= k_{stop}\), look at the respective elements for the starts and choose the lesser element - for this element increment the corresponding value of \(j_{start}\) or \(k_{start}\) and record the lesser element \(r\) - then look at the respective elements of the stops and choose the greater and save it as \(l\) - for this element decrement the corresponding value of \(j_{stop}\) or \(k_{stop}\).
If one array has been expended, just do this for just the remaining array. If both have been expended, stop.
Repeat step 2 until \(j_{start} > j_{stop}\) and \(k_{start} > k_{stop}\).
Take the mean of \(l\) and \(r\).
Implementation
My initial solution is
class Solution:
# NOTE: Input arrays should already be sorted.
def findMedianSortedArrays(
self,
list[int],
nums1: list[int],
nums2: -> float:
)
= len(nums1), len(nums2)
n1, n2 if n1 + n2 == 1:
if n1 != 0:
return nums1[0]
else:
return nums2[0]
= 0, 0
start_1, start_2 = n1 - 1, n2 - 1
stop_1, stop_2 = None, None
left, right
while True:
# If both, decide which one to decrement/increment
if start_1 <= stop_1 and start_2 <= stop_2:
= nums1[start_1], nums2[start_2]
a, b if a <= b:
= a
left += 1
start_1 else:
= b
left += 1
start_2
= nums1[stop_1], nums2[stop_2]
a, b if a >= b:
= a
right -= 1
stop_1 else:
= b
right -= 1
stop_2 elif start_1 < stop_1:
= nums1[start_1]
left = nums1[stop_1]
right
-= 1
stop_1 += 1
start_1 elif start_2 < stop_2:
= nums2[start_2]
left = nums2[stop_2]
right
-= 1
stop_2 += 1
start_2 elif stop_1 == start_1:
= right = nums1[stop_1]
left break
elif stop_2 == start_2:
= right = nums2[stop_2]
left break
else:
break
return (left + right) / 2 # type: ignore[operator]
however it did not rank very well in runtime with a sad \(38\%\) or memory with a horrific \(20\%\). However, my iterated solution simplified the logic and removed the initial step for trivial cases and did shockingly well. It beat \(94\%\) of submissions in runtime and \(99\%\) in memory.
class Solution:
# NOTE: Input arrays should already be sorted.
def findMedianSortedArrays(
self,
list[int],
nums1: list[int],
nums2: -> float:
)
= len(nums1), len(nums2)
n1, n2 if n1 + n2 == 1:
if n1 != 0:
return nums1[0]
else:
return nums2[0]
= 0, 0
start_1, start_2 = n1 - 1, n2 - 1
stop_1, stop_2 = None, None
left, right
while True:
# If both, decide which one to decrement/increment
if start_1 <= stop_1 and start_2 <= stop_2:
= nums1[start_1], nums2[start_2]
a, b if a <= b:
= a
left += 1
start_1 else:
= b
left += 1
start_2
= nums1[stop_1], nums2[stop_2]
a, b if a >= b:
= a
right -= 1
stop_1 else:
= b
right -= 1
stop_2 elif start_1 < stop_1:
= nums1[start_1]
left = nums1[stop_1]
right
-= 1
stop_1 += 1
start_1 elif start_2 < stop_2:
= nums2[start_2]
left = nums2[stop_2]
right
-= 1
stop_2 += 1
start_2 elif stop_1 == start_1:
= right = nums1[stop_1]
left break
elif stop_2 == start_2:
= right = nums2[stop_2]
left break
else:
break
return (left + right) / 2 # type: ignore[operator]