给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。
请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。
你可以假设 nums1 和 nums2 不同时为空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
中位数是 (2 + 3)/2 = 2.5
讲真的,这道题其实配不上难题,顶多算中档题里面偏难一点的,但是鬼知道我提交了多少次才完美通过。
这道题跟我高中做导数最后一道题一样,不知道要考虑多少种情况。一次一次来,leetcode好处就在于省的你想哪里做不到了,人家想到的肯定比你全。因此在上面刷题能锻炼自己。
思路:这道题难在给你限时,也就是时间复杂度要求为o(log(m+n)),答案给的太复杂,也太详细,我看不下去数学推论过程。如果不限时,很简单:将两个数组合并成一个数组,然后利用sort排序,取中位数即可。时间复杂度超出。因为sort函数的时间复杂度难以计算(sort融合了多种排序的优势,因此不同数据量速度不同),这里就不给时间复杂度的计算问题了。
还有一种思路,就是在构成新的数组的同时排好序,有点像二叉搜索树,但是这里没用树算法,直接进行比较,然后将数据存入相应的数组内部。时间复杂度是o(m+n)
当然,这种思路可以继续根据题意优化,笔者的代码也是如此写的:添加一个计数器count,当 i 和 j 之和超过原来两个数组数据量的一半,就可以停止继续比较,得出答案即可。时间复杂度是o((m+n)/2)······其实还是没做到o(log(m+n))
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size();
int m = nums2.size();
int sum = n + m;
int i = 0 , j = 0;
int count = 0;
vector<int> num;
double result = 0;
if(n!=0 && m!=0)
{
if(sum%2 == 0)
{
sum = sum/2;
while(i+j<sum)
{
if(i<n && j<m)
{
if(nums1[i] < nums2[j])
num.push_back(nums1[i++]);
else
num.push_back(nums2[j++]);
}
else if(i<n && j>=m)
num.push_back(nums1[i++]);
else if(i>=n && j<m)
num.push_back(nums2[j++]);
count++;
}
if(i<n && j<m)
{
if(nums1[i] < nums2[j])
num.push_back(nums1[i++]);
else
num.push_back(nums2[j++]);
}
else if(i<n)
num.push_back(nums1[i++]);
else if(j<m)
num.push_back(nums2[j++]);
result = (num[count-1] + num[count])/2.0;
}
else{
sum = sum/2;
while(i+j < sum)
{
if(i<n && j<m)
{
if(nums1[i] < nums2[j])
num.push_back(nums1[i++]);
else
num.push_back(nums2[j++]);
}
else if(i<n && j>=m)
num.push_back(nums1[i++]);
else if(i>=n && j<m)
num.push_back(nums2[j++]);
count++;
}
if(i<n && j<m)
{
if(nums1[i] < nums2[j])
num.push_back(nums1[i++]);
else
num.push_back(nums2[j++]);
}
else if(i<n)
num.push_back(nums1[i++]);
else if(j<m)
num.push_back(nums2[j++]);
result = num[count];
}
}
else if(n == 0)
{
if(m%2 != 0)
result = nums2[m/2];
else
result = (nums2[m/2-1] + nums2[m/2])/2.0;
}
else if(m == 0)
{
if(n%2 != 0)
result = nums1[n/2];
else
result = (nums1[n/2-1] + nums1[n/2])/2.0;
}
return result;
}
};
我承认我的代码仍有继续优化的空间,例如不用将数据存在新建的vector数组中,从而节省空间开销;也可以减少if-else的使用来增加程序的可读性·········但是我已经被胜利冲昏了头脑,不想再写了,等到我二刷 leetcode 的时候,再看看有没有什么其他更好的算法吧!!
附上答案:
class Solution {
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;
}
}