朴素解法
求中位数一般是用归并排序,按照类似快排的思想求第k/2大的数。但是由于给定的两个数组都是有序的,一般第一眼看到这个问题,最先想到的就是两个数组做排序,然后输出中位数。不得不说leetcode的数据也是仁慈,居然直接就过了……这个思路实在是太简单了,就不讲了,看代码就好了。
#include <string>
#include <iostream>
#include <vector>
using namespace std;
/*
显然,最简单的思路就是两者归并排序后直接求,得到的答案肯定是对的。
*/
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
vector<int> ans;
unsigned int i = 0,j = 0;
while(i<nums1.size()&&j<nums2.size())
{
if(nums1[i]<=nums2[j])
{
ans.push_back(nums1[i]);
i++;
}
else
{
ans.push_back(nums2[j]);
j++;
}
}
while(i<nums1.size())
{
ans.push_back(nums1[i]);
i++;
}
while(j<nums2.size())
{
ans.push_back(nums2[j]);
j++;
}
// for(unsigned int k = 0 ; k < ans.size();k++)
// {
// cout<<ans[k]<<endl;
// }
if(ans.size()%2==0)
{
return (double)(ans[ans.size()/2-1]+ans[ans.size()/2])/2;
}
else
{
return ans[ans.size()/2];
}
}
};
int main(void)
{
Solution s;
vector<int> a;
vector<int> b;
a.push_back(1);
a.push_back(2);
b.push_back(3);
// b.push_back(4);
cout<<s.findMedianSortedArrays(a,b)<<endl;
return 0;
}
二分法
这个是官方给的标准答案。
由中位数的定义可以推广出:
- 如果在集合中存在i将集合化为两个划分left和right,i为中位数当且仅当len(left(i))=len(right(i))且max(left(i))<=min(right(i))。
- 由此,如果是两个有序集合,则如果把这两个有序集合都用上面这种形式来写的话,如果它们组成的大集合仍然满足上面的形式,则这两个划分所在的分界点就是中位数。问题就转化到怎么求集合的划分上来了。
- 设这两个划分点为i,j;数组A长为n,数组B长为m,则有 i + j = n − i + m − j i+j=n-i+m-j i+j=n−i+m−j, B [ j − 1 ] ≤ A [ i ] 以 及 A [ i − 1 ] ≤ B [ j ] B[j−1]\leq A[i] 以及 A[i-1] \leq B[j] B[j−1]≤A[i]以及A[i−1]≤B[j]
- 所以问题就转化为了在[0,m]上搜索i,使得
B
[
j
−
1
]
≤
A
[
i
]
以
及
A
[
i
−
1
]
≤
B
[
j
]
,
其
中
j
=
n
+
m
−
2
i
2
B[j−1]\leq A[i] 以及 A[i-1] \leq B[j],其中j=\frac{n+m-2i}{2}
B[j−1]≤A[i]以及A[i−1]≤B[j],其中j=2n+m−2i
标准答案给的是二分的求法,跟我想到的也一样,不过我没写出来,直接用它的吧。
def median(A, B):
m, n = len(A), len(B)
if m > n:
A, B, m, n = B, A, n, m
if n == 0:
raise ValueError
imin, imax, half_len = 0, m, (m + n + 1) / 2
while imin <= imax:
i = (imin + imax) / 2
j = half_len - i
if i < m and B[j-1] > A[i]:
# i is too small, must increase it
imin = i + 1
elif i > 0 and A[i-1] > B[j]:
# i is too big, must decrease it
imax = i - 1
else:
# i is perfect
if i == 0: max_of_left = B[j-1]
elif j == 0: max_of_left = A[i-1]
else: max_of_left = max(A[i-1], B[j-1])
if (m + n) % 2 == 1:
return max_of_left
if i == m: min_of_right = B[j]
elif j == n: min_of_right = A[i]
else: min_of_right = min(A[i], B[j])
return (max_of_left + min_of_right) / 2.0