There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the meidan of the two sorted arrays. The overall run time complexity should O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n)).
You may assume nums1 and nums2 cannot be both empty.
nums1 = [1, 3]
nums2 = [2]
The median is 2.0
nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5
最容易想到的办法,将两个有序数组进行合并,取最中间的数(合并后奇数个元素)或者最中间两个数(合并后偶数个元素)的平均数即可。其中合并后元素的个数是可以计算的,因此只需要找出合并后的中间元素即可,无需开辟空间存储合并后的数组,最多两个元素的空间用来存储遍历到的最后两个元素。
class Solution {
public:
double findMedianSortedArrays(vector& nums1, vector& nums2) {
unsigned m = nums1.size(), n = nums2.size();
unsigned last = (m+n)/2+1;
unsigned i=0, j=0;
int meidans[2] = {0};
unsigned idx = 0;
while(idx < last)
{
if(i
执行结果:通过
执行用时:16ms,在所有C++提交中击败了84.66%的用户
内存消耗:7.3MB,在所有C++提交中击败了100.00%的用户
然而以上方法的时间复杂度为 O ( m + n ) O(m+n) O(m+n),达不到 O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n))的要求。
设两有序数组分别为 A = { A [ 0 ] , A [ 1 ] , . . . , A [ m ] } A = \{A[0], A[1], ..., A[m]\} A={A[0],A[1],...,A[m]}和 B = { B [ 0 ] , B [ 1 ] , . . . , B [ n ] } B = \{B[0], B[1], ..., B[n]\} B={B[0],B[1],...,B[n]},现将 A A A和 B B B都拆分为左右两部分即:
A = A l e f t + A r i g h t A = A_{left} + A_{right} A=Aleft+Aright,
A l e f t = { A [ 0 ] , A [ 1 ] , . . . , A [ i − 1 ] } A_{left} = \{A[0], A[1], ..., A[i-1]\} Aleft={A[0],A[1],...,A[i−1]}, A r i g h t = { A [ i ] , A [ i + 1 ] , . . . , A [ m ] } A_{right} = \{A[i], A[i+1], ..., A[m]\} Aright={A[i],A[i+1],...,A[m]}
且
B = B l e f t + B r i g h t B = B_{left} + B_{right} B=Bleft+Bright,
B l e f t = { B [ 0 ] , B [ 1 ] , . . . , B [ j − 1 ] } B_{left} = \{B[0], B[1], ..., B[j-1]\} Bleft={B[0],B[1],...,B[j−1]}, B r i g h t = { B [ j ] , B [ j + 1 ] , . . . , B [ n ] } B_{right} = \{B[j], B[j+1], ..., B[n]\} Bright={B[j],B[j+1],...,B[n]}
此时,令
L = A l e f t + B l e f t L = A_{left} + B_{left} L=Aleft+Bleft
R = A r g i h t + B r i g h t R = A_{rgiht} + B_{right} R=Argiht+Bright
若 m + n m+n m+n即 A A A和 B B B的总长度为偶数时,条件
s i z e ( L ) = s i z e ( R ) size(L) =size(R) size(L)=size(R)
m a x ( L ) ≤ m i n ( R ) max(L) \leq min(R) max(L)≤min(R)
满足,那么所寻找的中位数为:
m e d i a n = m a x ( L ) + m i n ( R ) 2 median = \frac{max(L)+min(R)}{2} median=2max(L)+min(R)
若 m + n m+n m+n即 A A A和 B B B的总长度为奇数时,条件
s i z e ( L ) = s i z e ( R ) + 1 size(L) =size(R)+1 size(L)=size(R)+1
m a x ( L ) ≤ m i n ( R ) max(L) \leq min(R) max(L)≤min(R)
满足,那么所寻找的中位数为:
m e d i a n = m a x ( L ) median = max(L) median=max(L)
又由于上述两组条件等价于以下三个条件:
条件一:
i + j = ( m − i ) + ( n − j ) ⇒ i + j = ⌊ m + n + 1 2 ⌋ i+j=(m-i) + (n-j) \Rightarrow i+j=\lfloor\frac{m+n+1}{2}\rfloor i+j=(m−i)+(n−j)⇒i+j=⌊2m+n+1⌋ ,当 m + n m+n m+n为偶数时
i + j = ( m − i ) + ( n − j ) + 1 ⇒ i + j = ⌊ m + n + 1 2 ⌋ i+j=(m-i) + (n-j) + 1 \Rightarrow i+j=\lfloor\frac{m+n+1}{2}\rfloor i+j=(m−i)+(n−j)+1⇒i+j=⌊2m+n+1⌋,当 m + n m+n m+n为奇数时
条件二:
假设 m ≤ n m \leq n m≤n,且 0 ≤ i ≤ m , 0 ≤ j ≤ n 0 \leq i \leq m, 0\leq j\leq n 0≤i≤m,0≤j≤n,
则对于 ∀ i ∈ [ 0 , m ] \forall i \in[0, m] ∀i∈[0,m],都有 j = ( ⌊ m + n + 1 2 ⌋ − i ) ∈ [ 0 , n ] j=(\lfloor\frac{m+n+1}{2}\rfloor-i)\in[0,n] j=(⌊2m+n+1⌋−i)∈[0,n]
条件三:
B [ j − 1 ] ≤ A [ i ] B[j-1]\leq A[i] B[j−1]≤A[i]
A [ i − 1 ] ≤ B [ j ] A[i-1]\leq B[j] A[i−1]≤B[j]
为了简化计算,假设 A [ i − 1 ] , B [ j − 1 ] , A [ i ] , B [ j ] A[i-1], B[j-1], A[i], B[j] A[i−1],B[j−1],A[i],B[j]总是存在 。对于 i = 0 , i = m , j = 0 , j = n i=0, i=m,j=0,j=n i=0,i=m,j=0,j=n这样的临界条件,只需规定 A [ − 1 ] = B [ − 1 ] = − ∞ A[-1]=B[-1]=-\infty A[−1]=B[−1]=−∞ , A [ m ] = B [ n ] = ∞ A[m]=B[n]=\infty A[m]=B[n]=∞即可。 因为其计算并不会影响 L L L和 R R R中的最大值或最小值产生影响。
最后程序需要计算的是:
在[0,m]中找到i,使得:
B[j-1]<=A[i]且A[i-1]<=B[j],其中j=(m+n+1)/2-i
同时上述条件也等价于
在[0,m]中找到最大的i,使得:
A[i-1]<=B[j],其中j=(m+n+1)2-i
因为:
当 i i i从 0 ∼ m 0\sim m 0∼m 递增时, A [ i − 1 ] A[i-1] A[i−1]递增, B [ j ] B[j] B[j]递减,所以一定存在一个最大的 i i i满足 A [ i − 1 ] ≤ B [ j ] A[i-1]\leq B[j] A[i−1]≤B[j];
而对于最大的 i i i,有 i + 1 i+1 i+1不满足,即代入 i + 1 i+1 i+1则有 A [ i ] > B [ j − 1 ] A[i]>B[j-1] A[i]>B[j−1],也就是 B [ j − 1 ] < A [ i ] B[j-1]B[j−1]<A[i]。
综上所述,在区间 [ 0 , m ] [0,m] [0,m]上对 i i i进行二分查找 ,找到最大的满足 A [ i − 1 ] ≤ B [ j ] A[i-1]\leq B[j] A[i−1]≤B[j]的 i i i值,得到了正确的划分有序数组 A A A和 B B B为有序数组左 L L L右 R R R两部分的方法。
class Solution {
#define MAX(a, b) ((a)>(b)?(a):(b))
#define MIN(a, b) ((a)<(b)?(a):(b))
public:
double findMedianSortedArrays(vector& nums1, vector& nums2) {
if (nums1.size() > nums2.size()){
return findMedianSortedArrays2(nums2, nums1);
}
unsigned m = nums1.size(), n = nums2.size();
int left = 0, right = m;
int maxL = 0, minR = 0;
while (left <= right){
// L = nums1[0, .., i-1], nums2[0, .., j-1]
// R = nums1[i, .., m-1], nums2[j, .., n-1]
int i = (left + right) / 2;
int j = (m + n + 1) / 2 - i;
int nums_i_1 = (i == 0 ? INT_MIN : nums1[i - 1]); // nums1[i-1]
int nums_i = (i == m ? INT_MAX : nums1[i]); // nums1[i]
int nums_j_1 = (j == 0 ? INT_MIN : nums2[j - 1]); // nums2[j-1]
int nums_j = (j == n ? INT_MAX : nums2[j]); // nums2[j]
if (nums_i_1 <= nums_j){
maxL = MAX(nums_i_1, nums_j_1);
minR = MIN(nums_i, nums_j);
left = i + 1;
}
else{
right = i - 1;
}
}
return ((m + n) & 1) == 0 ? (maxL + minR) / 2.0 : maxL;
}
执行结果:通过
执行用时:16ms,在所有C++提交中击败了84.42%的用户
内存消耗:7.1MB,在所有C++提交中击败了68.98%的用户
以上方法的时间复杂度为 O ( l o g m i n ( m , n ) ) O(log min(m,n)) O(logmin(m,n)),其中 m m m和 n n n另是数组 n u m s 1 nums1 nums1和 n u m s 2 nums2 nums2的长度。
空间复杂度为 O ( 1 ) O(1) O(1)。