問題
/*
* @lc app=leetcode.cn id=4 lang=cpp
* * [4] 尋找兩個有序數組的中位數
* * https://leetcode-cn.com/problems/median-of-two-sorted-arrays/description/
* * algorithms
* Hard (33.60%)
* Total Accepted: 37K
* Total Submissions: 110.2K
* Testcase Example: '[1,3]\n[2]'
* * 給定兩個大小爲 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
*
*
*/
思路1:歸併排序,合併有序數組,時間複雜度O(m+n),不符合要求
思路2:看到時間複雜度O(log(m+n)),首先可以想到二分法(分治思想)
-
把找中位數轉化爲找第 (m+n+1)/2 和 第 (m+n+2)/2 小元素的平均(這樣不用考慮奇偶的問題)
-
二分思想設計find_kth函數 假定整體數組c中歐前k個元素一半k/2在數組a,一半k/2在數組b
- 如果a[k/2] < b[k/2] 那麼 a[0]<=a[1]<=…<=a[k/2] <= b[k/2] 且 b[0]<=b[1]<=…<=b[k/2] 說明b[k/2] 至少是c中第k小的元素,所以a[0-k/2]都小於我們的目標值,可以去掉a[0-k/2],然後在剩下的元素中找第k/2小
- 同理如果a[k/2] > b[k/2] 所以b[0-k/2]都小於我們的目標值,可以去掉b[0-k/2],然後在剩下的元素中找第k/2小
-
如果數組a中個數不夠k/2,那麼b中小於目標元素的個數一定大於k/2,所以可以去掉b中前k/2小的元素,然後在剩下的元素中找第k/2小
-
同理如果數組b中個數不夠k/2,那麼a中小於目標元素的個數一定大於k/2,所以可以去掉a中前k/2小的元素,然後在剩下的元素中找第k/2小
完整代碼如下
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size();
int n = nums2.size();
if (nums1.empty()) {
if (n%2 != 0)
return 1.0*nums2[n/2];
return (nums2[n/2]+nums2[n/2-1])/2.0;
}
if (nums2.empty()) {
if (m%2 != 0)
return 1.0*nums1[m/2];
return (nums1[m/2]+nums1[m/2-1])/2.0;
}
int total = (m+n+1)/2;
int total2 = (m+n+2)/2;
// 轉換爲在兩個有序數組中尋找第k小元素(從1計數) (m+n+1)/2 (m+n+2)/2
return (find_kth(nums1,0,nums2,0,total)+find_kth(nums1,0,nums2,0,total2))/2.0;
}
double find_kth(vector<int> a, int a_begin, vector<int> b, int b_begin, int k) {
// a中無元素 b有序 直接在b中取第k小元素
if (a_begin > a.size()-1)
return b[b_begin+k-1];
if (b_begin > b.size()-1)
return a[a_begin+k-1];
// 第1小元素 就是找ab中最小元素的最小值
if (k == 1)
return min(a[a_begin],b[b_begin]);
if (a_begin+k/2-1 < a.size() && b_begin+k/2-1 < b.size()){
if(a[a_begin+k/2-1] < b[b_begin+k/2-1])
return find_kth(a,a_begin+k/2,b,b_begin,k-k/2);
else
return find_kth(a,a_begin,b,b_begin+k/2,k-k/2);
}
else if(a_begin+k/2-1 < a.size()){
return find_kth(a,a_begin+k/2,b,b_begin,k-k/2);
}else{
return find_kth(a,a_begin,b,b_begin+k/2,k-k/2);
}