這題挺有意思的,一開始想了半天怎麼處理細節,想了半天,沒想出來,要不暴力所有情況,結果特麼還跑的飛快。
這題看一眼肯定知道是二分,兩個有序數組,找合併之後的中位數。難搞的就是會出現相同數字,和數組長度是偶數。所以我就搞了一個函數 直接找第 k 個在哪,然後第K個在哪,因爲 第 k個可能在第一個數組,又有可能在第二個數組,所以要找兩次,找的時候把引用換一下就行了。
賊麻煩,細節太難處理了,細節處理我打在代碼註釋裏。
思想就是 在一個數組裏面二分中間值位置,通過在另一個數組裏面二分找小於等於當前值的數量和自己的下標相加可以得到在兩個數組合並之後的位置。
const int INF=0x3f3f3f3f;
class Solution {
public:
inline int get(int k,vector<int>& nums1, vector<int>& nums2){
int l=0,r=nums1.size()-1;
while(l<=r){
int mid=(l+r)/2;
int num=lower_bound(nums2.begin(),nums2.end(),nums1[mid])-nums2.begin(); //找第二個數組裏面小於等於num[mid]的個數
if(mid+num<=k){ //如果加起來的位置小於 k 說明這個數可能是要找的 因爲可能出現很多個相同的數字所以不能簡單的判等於
int t1=upper_bound(nums2.begin(),nums2.end(),nums1[mid])-nums2.begin(); //當前這個值加上相同的個數
int t2=upper_bound(nums1.begin(),nums1.end(),nums1[mid])-nums1.begin(); //當前這個值加上相同的在num2裏面的個數
if(t1+t2-1>=k)return nums1[mid]; //兩個數相加 -1 就是 位置,下標從 0 開始
/* 舉個例子
* {1,1,3,3} {1,1,3,3}
* 假設你要找 k=6
* mid = 2 num1[mid]=3 num=2 mid+num=4 <6
* 然後 t1 = 4 t2 = 4 t1+t2-1=7 7>=6 所以 4-7 之間都是相同的數
* 所以實際上 3 是找到的答案
*
* */
l=mid+1;
}
else r=mid-1;
}
return -INF;
}
inline int Max(int k,vector<int>& nums1, vector<int>& nums2){
// 因爲我如果沒有在num1 裏面找到 下標剛好爲 k 的值就會返回-INF,所以直接取個MAX 就是答案
// 交換一下引用就相當於從 num2 裏面找排名第k的值了
return max(get(k,nums1,nums2),get(k,nums2,nums1));
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int k=(nums1.size()+nums2.size())/2;
if((nums1.size()+nums2.size())%2==0){ //如果偶數個 就找 兩個值
int t1=Max(k,nums1,nums2),t2=Max(k-1,nums1,nums2);
return (Max(k,nums1,nums2)+Max(k-1,nums1,nums2))/2.0;
}
else return Max(k,nums1,nums2);
}
};