Photo by Azharul Islam on Unsplash
Exploring LeetCode: Median of Two Sorted Arrays
Exploring the Depths of Coding: LeetCode's Median of Two Sorted Arrays
Introduction:
The "Median of Two Sorted Arrays" problem holds significant value in the realm of algorithmic programming. It presents a captivating challenge that requires finding the median value, a vital statistical measure with practical implications in various domains. The ability to solve this problem empowers us to delve into data analysis, make informed decisions, and optimize algorithms to tackle real-world scenarios effectively. In this blog, we will delve into the essence of the "Median of Two Sorted Arrays" problem, exploring its relevance in statistical analysis, finance, healthcare, and data science. By understanding its significance, we can unlock new insights and strengthen our problem-solving skills in algorithmic programming.
Problem Overview
Question:
Given two sorted arrays
nums1
andnums2
of sizem
andn
respectively, return the median of the two sorted arrays.The overall run time complexity should be
O(log (m+n))
.
Example 1:
Input: nums1 = [1,3], nums2 = [2] Output: 2.00000 Explanation: merged array = [1,2,3] and median is 2.
Example 2:
Input: nums1 = [1,2], nums2 = [3,4] Output: 2.50000 Explanation: merged array = [1,2,3,4] and median is (2 + 3) / 2 = 2.5.
Constraints:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-10<sup>6</sup> <= nums1[i], nums2[i] <= 10<sup>6</sup>
Brute Force Approach - Bubble Sort and Find Median
The core concept of the problem involves two fundamental steps:
Merging the two arrays: Initially, we need to combine the given arrays into a single, unified array. This consolidation allows us to work with a comprehensive dataset that includes all the elements.
Sorting the merged array: Following the merging step, we proceed to sort the combined array in ascending order. Sorting is essential for arranging the elements properly and facilitating the determination of the median.
Determining the median: Once the array is sorted, we can identify the median value. If the length of the combined array is odd, the median corresponds to the middle element. However, if the length is even, the median is calculated by averaging the two middle elements.
Now let's discuss the step-by-step process of the brute-force solution:
Combining the arrays: We begin by merging the elements of
nums1
andnums2
into a single array, which we refer to asjoinedArray
. This consolidation allows us to work with a unified dataset.Sorting the array: To ensure the elements are in the desired order, we proceed to sort
joinedArray
. In this brute-force approach, we employ the bubble sort algorithm, a simple yet less efficient sorting technique. The resulting sorted array is stored in the variablesortedArray
.Determining the median value: Our objective is to find the median, which differs based on the size of
sortedArray
. If the size is odd, we adopt the following approach:Calculate the middle index by dividing the size of
sortedArray
by 2.Obtain the element located at the middle index in
sortedArray
, which represents the median value.
However, when the size of sortedArray
is even, a slightly different approach is necessary:
Compute the index of the first middle element by subtracting 1 from the size of
sortedArray
divided by 2.Determine the median by calculating the average of the element at the first middle index and the following element.
Below is the provided code snippet for reference:
var findMedianSortedArrays = function(nums1, nums2) {
let middleValue = 0
const joinedArray = nums1.concat(nums2)
const sortedArray = bubbleSort(joinedArray)
if(sortedArray.length%2 !== 0){
var getDecimal = Math.floor(sortedArray.length/2)
middleValue = sortedArray[getDecimal]
} else {
var split = (sortedArray.length/2) - 1
var median = (sortedArray[split] + sortedArray[split+1]) / 2
middleValue = median
}
return middleValue
};
function bubbleSort(arr) {
const length = arr.length;
for (let i = 0; i < length - 1; i++) {
for (let j = 0; j < length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
const temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
What is the time and space complexity of this solution?
Time Complexity:
The
bubbleSort
function uses the Bubble Sort algorithm to sort thejoinedArray
, which has a length ofm + n
, wherem
is the length ofnums1
andn
is the length ofnums2
.Bubble Sort has an average and worst-case time complexity of O(n^2), where
n
is the number of elements in the array.In the worst case, the nested loops in
bubbleSort
will iterate (m + n) times.Therefore, the time complexity of sorting the array is O((m + n)^2).
Space Complexity:
The space complexity of the code is determined by the extra space used for the
joinedArray
andsortedArray
variables, as well as themiddleValue
variable.The
joinedArray
variable holds the merged array ofnums1
andnums2
, which requires space form + n
elements.The
sortedArray
variable holds the sorted version of thejoinedArray
, still requiring space form + n
elements.The
middleValue
variable requires space for a single element.Therefore, the space complexity is O(m + n).
Optimal Approach - Merge Sort and Find Median
Merge sort is widely regarded as a superior sorting algorithm compared to bubble sort due to its efficiency and reliability. The key advantage of merge sort lies in its solid time complexity, making it more suitable for sorting large arrays. With a time complexity of O(n log n), merge sort excels in breaking down the array into smaller, sorted segments before merging them back together. This approach ensures a streamlined and efficient sorting process. In contrast, bubble sort's time complexity of O(n^2) makes it less efficient, as it requires multiple iterations and element comparisons. As a result, merge sort stands as a sorted and solid choice for sorting tasks, particularly when handling substantial data sets.
Below is the provided code snippet for reference:
var findMedianSortedArrays = function(nums1, nums2) {
let middleValue = 0
const joinedArray = nums1.concat(nums2)
const sortedArray = mergeSort(joinedArray)
if(sortedArray.length%2 !== 0){
var getDecimal = Math.floor(sortedArray.length/2)
middleValue = sortedArray[getDecimal]
} else {
var split = (sortedArray.length/2) - 1
var median = (sortedArray[split] + sortedArray[split+1]) / 2
middleValue = median
}
return middleValue
};
function mergeSort(arr){
if(arr.length <= 1){
return arr
}
const mid = Math.floor(arr.length/2)
const left = arr.slice(0,mid)
const right = arr.slice(mid)
const sortedLeft = mergeSort(left)
const sortedRight = mergeSort(right)
return merge(sortedLeft, sortedRight)
}
function merge(left, right) {
let result = [];
let i = 0;
let j = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
result.push(left[i]);
i++;
} else {
result.push(right[j]);
j++;
}
}
while (i < left.length) {
result.push(left[i]);
i++;
}
while (j < right.length) {
result.push(right[j]);
j++;
}
return result;
}
What is the time and space complexity of this solution?
Time Complexity:
The
mergeSort
function uses the Merge Sort algorithm to sort thejoinedArray
, which has a length ofm + n
, wherem
is the length ofnums1
andn
is the length ofnums2
.Merge Sort has an average and worst-case time complexity of O(n log n), where
n
is the number of elements in the array.In the worst case, the
mergeSort
function will recursively split the array until it reaches arrays of size 1, which takes log(n) recursive calls.The merging step in the
merge
function takes O(n) time to merge the two sorted arrays.Therefore, the time complexity of sorting the array using Merge Sort is O((m + n) log(m + n)).
Space Complexity:
The space complexity of the code is determined by the extra space used for the
joinedArray
,sortedArray
, and the recursive calls in themergeSort
function.The
joinedArray
variable holds the merged array ofnums1
andnums2
, which requires space form + n
elements.The
sortedArray
variable holds the sorted version of thejoinedArray
, still requiring space form + n
elements.The
mergeSort
function uses recursive calls, and each call creates new slices of the input array, requiring additional space for those slices.However, the overall space used by the recursive calls is limited to O(log(m + n)), as the array is divided into halves.
Therefore, the space complexity is O((m + n) + log(m + n)), which simplifies to O(m + n).
Test Cases
To solidify your knowledge about it, it is recommended to try out various test cases.
Test Case 1: nums1 = [1, 3] nums2 = [2] Expected Output: 2.0
Test Case 2: nums1 = [1, 2] nums2 = [3, 4] Expected Output: 2.5
Test Case 3: nums1 = [0, 0] nums2 = [0, 0] Expected Output: 0.0
Test Case 4: nums1 = [] nums2 = [1] Expected Output: 1.0
Test Case 5: nums1 = [2] nums2 = [] Expected Output: 2.0
Test Case 6: nums1 = [1, 2, 5, 9] nums2 = [3, 4, 7, 8] Expected Output: 5.0
Test Case 7: nums1 = [10, 20, 30] nums2 = [40, 50, 60] Expected Output: 35.0
Test Case 8: nums1 = [1, 3, 5] nums2 = [2, 4, 6, 8] Expected Output: 4.0
Test Case 9: nums1 = [1, 3, 5, 7] nums2 = [2, 4, 6, 8] Expected Output: 4.5
Test Case 10: nums1 = [1, 3, 5, 7, 9] nums2 = [2, 4, 6, 8, 10] Expected Output: 5.5
Conclusion
The brute force solution can be summarized as follows: the code has a time complexity of O((m + n) log(m + n)), implying that the running time increases logarithmically with the size of the input arrays. In terms of space complexity, it is O(m + n), indicating that the space usage grows linearly with the size of the input arrays. By utilizing Merge Sort instead of Bubble Sort, the code employs a more efficient sorting algorithm, especially beneficial for larger arrays.