4. Median of Two Sorted Arrays
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
You may assume nums1 and nums2 cannot be both empty.
Example 1:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5
我的解决方案,就是重新将数组A/B重新排序,然后获取中间值。
public double FindMedianSortedArrays(int[] nums1, int[] nums2)
{
int num1_length = nums1.Length;
int num2_length = nums2.Length;
int maxlength = num1_length > num2_length ? num1_length : num2_length;
int[] newnums = new int[num1_length + num2_length];
int target_length = 0;
if (maxlength == 0) return 0.00d;
for (int i = 0; i < maxlength; i++)
{
if (num1_length ==0|| num2_length ==0|| nums1[0] <= nums2[0]|| nums1[0] <= nums2[num2_length - 1])
{
handleArray(ref nums1, ref newnums, ref target_length, i);
handleArray(ref nums2, ref newnums, ref target_length, i);
}
else
{
handleArray(ref nums2, ref newnums, ref target_length, i);
handleArray(ref nums1, ref newnums, ref target_length, i);
}
}
if (target_length % 2==0)
{
return Math.Round((Convert.ToDouble(newnums[target_length / 2 - 1] + newnums[target_length / 2]) / 2),2);
}
else
{
return Convert.ToDouble(newnums[target_length / 2]);
}
}
时间复杂度为O(m+n),显然还是不行。
Solution in LeetCode
Approach 1: Recursive Approach
要解决问题,首先我们得清楚了解median的含义
分成两块相同大小的块,而且其中一块大于另外一块。(如下图A,B)
如把A,B分别切分为相等的两块
left_A | right_A
A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1]
left_B | right_B
B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1]
假设A块的大小为m,B块的大小为n,那我们就可以得出
\text{len}(\text{left\_A}) = i, \text{len}(\text{right\_A}) = m - ilen(left_A)=i,len(right_A)=m−i.
当i=0时,left_A为空;当i=m时,right_A为空。
同理,B块也是一样。
如果以下两个条件成立
\text{len}(\text{left\_part}) = \text{len}(\text{right\_part})len(left_part)=len(right_part)
\max(\text{left\_part}) \leq \min(\text{right\_part})max(left_part)≤min(right_part)
那么可以得出
接下来,我们逐一分析两个数组之间的情况,如果数组A,B如例子所示,那么就满足以下两个条件:
如A={2,3} B={1,4},i=(0+2)/2=1,j=(2+2+1)/2-1=1,B[0]=1<=A[1]=2 A[0]=2<=B[1]=4
这个时候,你会想问"为什么n必须大于等于m"?因为这样j的索引项出超出范围了。如A={2,3} B={4},i=1,j=1,那么b[1]就是出界了。
接下来,我们就按照[0,m]的范围i~j一直循环下去:
-
令imin=0,imax=m, 范围就是[0,m]
-
令i=(imin+imax)/2,j=(m+n+1)/2-i
-
我们接下来遇到以下三种情况:
- B[j−1]≤A[i] and \text{A}[i-1] \leq \text{B}[j]A[i−1]≤B[j] ,也就是说我们已经找到目标i了。
- B[j−1]>A[i] ,意味着A块可能很小,我们需要增加i,去看一下B[j−1]>A[i]
- A[i−1]>B[j],意味着B块可能很小,我们需要减少i,再看看A[i−1]>B[j]
-
如果i找到了,那么就可以返回结果了
当m+n是偶数时,需要左边的Max_Left和右边的Min_Left的平均值。
当m+n是奇数时,只需要拿左边的Max_Left即可,因为Median就在块中。
接下来,我需要考虑下特殊情况,如i=0/j=0/i=m/j=n的情况。
-
当i=0时,也就是说A_Left为空,直接可以得出Max_Left=B[j-1]
-
当j=0时,也就是说B_Left为空,直接可以得出Max_Right=A[i-1]
-
当i=m时,也就是说A_Right为空,直接可以得出Max_Right=B[j]
-
当j=n时,也就是说B_Right为空,直接可以得出Max_Right=A[i]
算法如下:
public double FindMedianSortedArrays(int[] A, int[] B)
{
int m = A.Length;
int n = B.Length;
if (m > n)
{ // to ensure m<=n
int[] temp = A; A = B; B = temp;
int tmp = m; m = n; n = tmp;
}
int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
while (iMin <= iMax)
{
int i = (iMin + iMax) / 2;
int j = halfLen - i;
if (i < iMax && B[j - 1] > A[i])
{
iMin = i + 1; // i is too small
}
else if (i > iMin && A[i - 1] > B[j])
{
iMax = i - 1; // i is too big
}
else
{ // i is perfect
int maxLeft = 0;
if (i == 0) { maxLeft = B[j - 1]; }
else if (j == 0) { maxLeft = A[i - 1]; }
else { maxLeft = Math.Max(A[i - 1], B[j - 1]); }
if ((m + n) % 2 == 1) { return maxLeft; }
int minRight = 0;
if (i == m) { minRight = B[j]; }
else if (j == n) { minRight = A[i]; }
else { minRight = Math.Min(B[j], A[i]); }
return (maxLeft + minRight) / 2.0;
}
}
return 0.0;
}