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)).
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
思路
- 暴力算法:逐一遍历元素,将两个数组合并成一个有序数组。
- 复杂性分析:
- 时间复杂度:O(n*m).【不符合题目要求】
- 空间复杂度:O(1).
题解
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
vector<int> nums = nums1;
for (int i=0; i < nums2.size(); i++) {
bool found = 0;
for (std::vector<int>::iterator it = nums.begin(); it != nums.end(); ++it) {
if (nums2[i] < *it) {
nums.insert(it, nums2[i]);
found = 1;
break;
}
}
if (!found) {
nums.push_back(nums2[i]);
}
}
double result = 0;
int size = nums.size();
if (size%2 == 0) {
result = (double)(nums[size/2] + nums[size/2 - 1]) / 2;
} else {
result = nums[size/2];
}
return result;
}
};
优化
思路
上述方法的时间主要消耗在排序上,但事实上我们只需要找到第k大的数,而且两个给定数组已经排好序,所以不需要全排序的操作,直接搜寻即可。可用类似二分查找的方法将时间复杂度降至O(log(m+n))。
代码
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int len1=nums1.size();
int len2=nums2.size();
int len=len1+len2;
if(len & 1) return findKth(nums1,0,nums2,0,len/2+1);
return (findKth(nums1,0,nums2,0,len/2)+findKth(nums1,0,nums2,0,len/2+1))/2;
}
double findKth(vector<int>& nums1,int i1,vector<int>& nums2,int i2,int k){
if(i1>=nums1.size()) return nums2[i2+k-1];
if(i2>=nums2.size()) return nums1[i1+k-1];
if(k==1) return min(nums1[i1],nums2[i2]);
int key1=i1+k/2-1>=nums1.size()?INT_MAX:nums1[i1+k/2-1];
int key2=i2+k/2-1>=nums2.size()?INT_MAX:nums2[i2+k/2-1];
if(key1<key2) return findKth(nums1,i1+k/2,nums2,i2,k-k/2);
return findKth(nums1,i1,nums2,i2+k/2,k-k/2);
}
};
反思
- 查找思路
对于一个长度为 n 的已排序数列 a,若 n 为奇数,中位数为 a[n / 2 + 1] , 若 n 为偶数,则中位数 (a[n/2] + a[n/2 + 1]) / 2。
求两个数组的中位数,不妨设数列 A 元素个数为 n,数列 B 元素个数为 m,各自升序排序,则中位数则为第 (n+m)/2 小的数。因此,转化为在两个数列中求出第 K 小的元素便可以解决该问题。
取 A[k / 2] B[k / 2] 比较,如果 A[k / 2] > B[k / 2] 那么,所求的元素必然不在 B 的前 k/2 个元素中(证明反证法);反之,必然不在 A 的前 k/2 个元素中,于是我们可以将 A 或 B 数列的前 k/2 元素删去,求剩下两个数列的 k - k/2小元素,于是得到了数据规模变小的同类问题,递归解决。
如果 k/2 大于某数列的个数,所求元素必然不在另一数列的前 k/2 个元素中,同上操作即可。 - 转变思路,灵活运用。