题目
这个还是一个分治的问题,但是难点在于分谁。
一般的做题思路是对数组进行二分,但是这个题却要对查找的中间这个数进行二分,比较反常理所以比较难。
leetcode上也同样有这个题目:
如果把两个数组遍历一遍,放在同一个数组里。那这样空间和时间都占有了
O
(
m
+
n
)
O(m+n)
O(m+n)
但如果直接比较的过程中输出第
(
m
+
n
+
1
)
/
2
(m+n+1)/2
(m+n+1)/2个数,空间降低到
O
(
1
)
O(1)
O(1)了,但时间方面还是
O
(
m
+
n
)
O(m+n)
O(m+n)。所以要用分治的想法将其变为
O
(
l
o
g
(
m
+
n
)
)
O(log(m+n))
O(log(m+n))
但就像之前说的,第一个难点在于将找中位数的问题变为找两个数组中第K数,然后想到对K这个数进行二分。
第二个难点当然就在于想到二分K后,怎么再具体的实现。
比较两个数组k / 2处的值,如果A[k/2]大于B[k/2],那么最糟糕的情况,就是B[k/2]前边的数和A[k/2]前边的数都比B[k/2]小。那也才k-2个数,达不到第K个数。因此B[k/2]及其之前的数都可以扔掉了。这就是二分K的方式。
但要考虑三种特殊情况:
- 其中一个为长度为0了,直接从另一个数组找第K个数
- k=1的时候,不用除2了,直接选两个数组分别第一个元素的最小值
- 当选k/2的时候,如果超过了其中一个数组的长度,那就比较其结尾的数,另一个数组中索引的位置对应后移。
class Solution {
public:
int medianSearch(vector<int>& S1 , vector<int>& S2) {
int m = S1.size();
int n = S2.size();
return findKthNum(S1, 0, m-1, S2, 0, n-1, (m+n+1)/2);
}
int findKthNum(vector<int>& S1, int start1, int end1, vector<int>& S2, int start2, int end2, int k){
int len1 = end1-start1+1;
int len2 = end2-start2+1;
if(len1==0) return S2[start2+k-1];
if(len2==0) return S1[start1+k-1];
if(k==1)return min(S1[start1], S2[start2]);
int index1 = start1 + min(k/2, len1) -1;
int index2 = start2 + min(k/2, len2) -1;
if(S1[index1]<=S2[index2]){
return findKthNum(S1, index1+1, end1, S2, start2, end2, k-(index1-start1+1));
}else{
return findKthNum(S1, start1, end1, S2, index2+1, end2, k-(index2-start2+1));
}
}
};```