—— 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,因此沒有問題。