—— write for my baby, mua
[题目]
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
[中文翻译]
给定两个有序的数组nums1和nums2,数组大小分别为m、n。
找到两个数组的中位数。时间复杂度需要满足O(log(m+n))。
例子 1:
nums1 = [1, 3] nums2 = [2] 中位数为 2.0
Example 2:
nums1 = [1, 2] nums2 = [3, 4] 中位数为 (2 + 3)/2 = 2.5
[解题思路]
O(m+n)
直接的想法就是merge。循环地比较队顶元素,弹出小的,直到获得中位数。
O(log(m+n))
merge的算法,每次弹出的元素,是一个有序的序列,我们在获得中位数的同时,也将之前的元素排了序,但我们实际上只需要获得中位数,因此merge算法是有冗余的,也就是有多余的比较的。
要取得中位数,实际上就是需要获得第(m+n)/2小的数字,所以我们的目的,就是剔除前(m+n)/2-1小的数字,merge的问题在于,每次只弹出了一个元素,因此我们考虑,每次尽可能多地剔除元素。
设需要获得第k小的元素,剔除前k-1个元素。实际上,我们最多一次可以剔除k/2个元素。比较nums1[k/2]和nums2[k/2],如果nums1[k/2]较小,则可剔除nums1的前k/2个元素;否则剔除nums2的前k/2个元素。
可以证明,第k小的元素一定不在被剔除的k/2个元素中,因为在nums1[1..k/2]和nums2[1..k/2]一共k个元素中,如果存在第k小的元素,则一定是这k个元素中最大的一个,而剔除的规则保证了最大的一个是被保留的。
剔除完k/2个元素后,问题就转化为,在剩下的序列中,求第(k-k/2)小的元素,可见可以循环/递归地解决。
直到最后,需要求第1小的元素,就不需要剔除元素了,递归结束。时间复杂度为O(logk)
[C++代码]
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
double res;
int i = -1, j = -1;
int index;
if (0 == (nums1.size() + nums2.size()) % 2)
index = (nums1.size() + nums2.size()) / 2;
else
index = (nums1.size() + nums2.size()) / 2 + 1;
while (index > 1) {
int step = index / 2;
if (i + 1 >= nums1.size()) {
j += index - 1;
break;
}
if (j + 1 >= nums2.size()) {
i += index - 1;
break;
}
if (i + step >= nums1.size())
step = nums1.size() - 1 - i;
if (j + step >= nums2.size())
step = nums2.size() - 1 - j;
if (nums1.at(i + step) < nums2.at(j + step))
i = i + step;
else
j = j + step;
index -= step;
}
i++; j++;
if (0 == (nums1.size() + nums2.size()) % 2) {
if (i >= nums1.size())
res = nums2.at(j++);
else if (j >= nums2.size())
res = nums1.at(i++);
else if (nums1.at(i) < nums2.at(j))
res = nums1.at(i++);
else
res = nums2.at(j++);
if (i >= nums1.size())
res += nums2.at(j);
else if (j >= nums2.size())
res += nums1.at(i);
else
res += (nums1.at(i) < nums2.at(j)) ? nums1.at(i) : nums2.at(j);
res /= 2;
}
else {
if (i >= nums1.size())
res = nums2.at(j++);
else if (j >= nums2.size())
res = nums1.at(i++);
else if (nums1.at(i) < nums2.at(j))
res = nums1.at(i++);
else
res = nums2.at(j++);
}
return res;
}
};
[注意]
代码16行和21行,不能写成i >= nums1.size() - 1,原因是nums1.size()是size_t一般为unsigned int类型(反正是个无符号整,因为size不可能为负),在比较的时候,i会被自动转换成unsigned int进行比较,i的初始值为-1,转换成unsgined int之后是最大的无符号整型,因此不会达到我们逻辑上的目的。而在我们的程序中i+1>=0,因此没有问题。