LeetCode第四题 两个排序数组的中位数
有两个大小为 m 和 n 的排序数组 nums1 和 nums2 。
请找出两个排序数组的中位数并且总的运行时间复杂度为 O(log (m+n)) 。
示例 1:
nums1 = [1, 3]
nums2 = [2]中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]中位数是 (2 + 3)/2 = 2.5
方法一
解题思路
对于这道题,难点在于运行时间复杂度,使用排序算法,将两个数值合并排序,在选出中位数的方法,显然不符合时间复杂度的要求,因此,我们参考了网址中的解题方法,时间复杂度符合要求。
首先,确保两个有序数组的长度m<=n,如果不是这样,交换两个数组位置,这对我们以后的讨论,带来简便。
使用变量i和j分别代表了数组A和数组B的下标,其中j=(m+n+1/2)-i,之所以这样做,是因为中位数将两个数组分成长度相等的两部份,也就是说数组A的左半部分加上数组B的左半部分等于,数组A的右半部分加上数组B的右半部分。
另外使用了iMin和iMax表示了数组A的下标i的取值范围,使用一个while循环,不断的更新i和j的值,从而找到中位数的下标位置。
更新下标时,通常会遇到三种情况:
1. 下标i的值太小了。此时,(i < m && j > 0 && B[j-1] > A[i])
也就是说数组B的第j-1个值(左侧)都比数组A的第i个值(右侧)大,此时需要增大i的值。
2. 下标i的值太大了。此时,(i > 0 && j < n && A[i-1]> B[j])
也就是说数组A的中位数左侧的大于数组B的中位数右侧的值了,此时需要减小i的值。
3. 除了上述的两种情况外,此时的下标i和j刚刚好。
在情况三下,需要进一步讨论中位数的取值,此时又分两种情况:
-. m+n
是奇数。只要找到左侧最大值即可。
-. m+n
是偶数。找到左侧最大值和右侧最小值,返回平均值。
Java
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length, n = nums2.length;
if (m > n)
return findMedianSortedArrays(nums2, nums1);/// 保证m<=n
int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
while (iMin <= iMax) {
int i = (iMax + iMin) / 2;
int j = halfLen - i;
if (i < m && j > 0 && nums2[j - 1] > nums1[i]) {
iMin = iMin + 1;
} else if (i > 0 && j < n && nums1[i - 1] > nums2[j]) {
iMax = iMax - 1;
} else {
double maxLeft = 0;
if (i == 0) {
maxLeft = nums2[j - 1];
} else if (j == 0) {
maxLeft = nums1[i - 1];
} else {
maxLeft = Math.max(nums1[i - 1], nums2[j - 1]);
}
if ((m + n) % 2 == 1)
return maxLeft;
double minRight = 0;
if (i == m) {
minRight = nums2[j];
} else if (j == n) {
minRight = nums1[i];
} else {
minRight = Math.min(nums1[i], nums2[j]);
}
return (maxLeft + minRight) / 2.0;
}
}
return 0.0;
}
Python
class Solution(object):
def findMedianSortedArrays(self, A, B):
m, n = len(A), len(B)
if (m > n):
return Solution().findMedianSortedArrays(B, A)
iMin, iMax, halfLen = 0, m, int((m + n + 1) / 2)
while iMin <= iMax:
i = int((iMax + iMin) / 2)
j = int(halfLen - i)
if i < m and j > 0 and B[j - 1] > A[i]:
iMin = iMin + 1
elif i > 0 and j < n and A[i - 1] > B[j]:
iMax = iMax - 1
else:
if i == 0:
maxLeft = B[j - 1]
elif j == 0:
maxLeft = A[i - 1]
else:
maxLeft = max(A[i - 1], B[j - 1])
if (m + n) % 2 == 1:
return maxLeft
if i == m:
minRight = B[j]
elif j == n:
minRight = A[i]
else:
minRight = min(A[i], B[j])
return (maxLeft + minRight) / 2.0
C++
class Solution
{
public:
double findMedianSortedArrays(vector<int>& A, vector<int>& B)
{
int m = A.size(), n = B.size();
if(m>n)return findMedianSortedArrays(B, A);
int iMin = 0, iMax = m, halfLen = (m+n+1)/2;
while(iMin<=iMax)
{
int i = (iMin+iMax)/2;
int j = halfLen - i;
if(i<m&&j>0&& B[j-1]>A[i])
{
iMin = iMin + 1;
}
else if(i>0&&j<n&&A[i-1]>B[j])
{
iMax = iMax - 1;
}
else
{
double maxLeft = 0;
if(i==0)
{
maxLeft=B[j-1];
}
else if(j==0)
{
maxLeft=A[i-1];
}
else
{
maxLeft=max(A[i-1],B[j-1]);
}
if((m+n)%2==1)return maxLeft;
double minRight = 0;
if(i==m)
{
minRight = B[j];
}
else if(j==n)
{
minRight=A[i];
}
else
{
minRight = min(A[i],B[j]);
}
return (maxLeft+minRight)/2.0;
}
}
return 0.0;
}
};
方法二
本方法更加简便有效。因为数组A和数组B都是排序好的,因此我们使用一个数组C,有序的将A和B放进C中,最终取出C中的中位数,超级简单。
java
public double findMedianSortedArrays(int[] A, int[] B) {
int m = A.length, n = B.length;
int[] C = new int[m+n];
int i=0,j=0;
while(true){
if(i>=m||j>=n) break;
if(A[i]<B[j]){
C[i+j]=A[i];
i++;
}else{
C[i+j]=B[j];
j++;
}
}
if(i==m){
for(int k=j;k<n;k++){
C[i+k]=B[k];
}
}else{
for(int k=i;k<m;k++){
C[j+k]=A[k];
}
}
if((m+n)%2==1){
return C[(m+n)/2];
}else{
return (C[(m+n)/2-1]+C[(m+n)/2])/2.0;
}
}
C++
double findMedianSortedArrays(vector<int>& A, vector<int>& B)
{
int m = A.size(), n = B.size();
vector<int>C = vector<int>();
int i=0,j=0;
while(true)
{
if(i>=m||j>=n)break;
if(A[i]<B[j])C.push_back(A[i++]);
else C.push_back(B[j++]);
}
if(i==m)
for(int k=j; k<n; k++)
C.push_back(B[k]);
else
for(int k=i; k<m; k++)
C.push_back(A[k]);
if((m+n)%2==1)
return C[(m+n)/2];
else
return (C[(m+n)/2-1]+C[(m+n)/2])/2.0;
}
python
class Solution(object):
def findMedianSortedArrays(self, A, B):
m, n = len(A), len(B)
i, j = 0, 0
C = [0 for x in range(0, m+n)]
while True:
if (i >= m or j >= n):
break;
if (A[i] < B[j]):
C[i+j] = A[i]
i = i+1
else:
C[i+j] = B[j]
j = j+1
if (i == m):
for k in range(j, n):
C[i+k] = B[k]
else:
for k in range(i, m):
C[j+k] = A[k]
if ((m+n)%2==1):
return C[int((m+n)/2)]
else:
return (C[int((m+n)/2-1)]+C[int((m+n)/2)])/2.0