折半查找
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int k = (nums1.length+nums2.length)/2;
if((nums1.length+nums2.length)%2==1){
return serch_k(nums1,nums2,k+1);
}
else{
double mid = (serch_k(nums1,nums2,k)+serch_k(nums1,nums2,k+1))/2.0;
return mid;
}
}
public int serch_k(int[] nums1,int[] nums2,int k){
int mid ;
int left1=0,left2=0;
int number1,number2;
while(true){
if(left1==nums1.length){
return nums2[left2+k-1];
}
if(left2==nums2.length){
return nums1[left1+k-1];
}
if(k==1){
return Math.min(nums1[left1],nums2[left2]);
}
mid = k/2;
number1=Math.min(left1+mid,nums1.length)-1;
number2=Math.min(left2+mid,nums2.length)-1;
if(nums1[number1]<=nums2[number2]){
k=k-number1-1+left1;
left1=number1+1;
}else{
k=k-number2-1+left2;
left2=number2+1;
}
}
}
}
2.算法思考(以下分析过程假定数组元素从1开始)
- 要寻找一个数组的中位数,就是将数组按从小到大排列,然后找到中间的数字(先只考虑有奇数个数字),也就是求第k =(n/2)+ 1个元素
- 所以求中位数的问题就转换为求第k小的元素的问题
- 考虑有序数组的性质 首先,数组可以随机存取,而数组是有序的,则可以直接找到第k小的元素,即a[k-1]
- 问题是寻找第k个元素(以下第k个元素,代表第k个小的元素),而寻找第k个元素,我们就不关心前k-1个元素
3.二分过程
- 现在是两个有序数组,去从中寻找第k个元素,我们要想办法把问题转换成寻找第1个元素或把一个数组给消去
- 我们怎么消去数组或减小k的值,在算法思考(4.)中提到,我们不关心前k-1个元素,那我们就是要消去俩个数组中的前k-1个元素
- 如何去消去k-1个元素,(举个例子,我们拿第一个数组中第一个元素,和第二个数组中第一个元素做对比,我们消去小的那个元素,然后将k减1),但是很明显一次消去一个元素效率太低,我们要尽可能多的消去元素,我们不妨将两个数组的第k/2个元素进行对比,将小的元素的前面元素包括自身全部消去,因为a[k/2]<b[k/2],比b[k/2]小的元素有k/2-1个,所以比a[k/2]小的元素最多有k-1个,即b[k/2]前面的所有元素都比a[k/2]前面的元素都大。
- 根据这种想法,我们就可以不停的消减k值,知道k为1,我们就可以直接通过比较两个数组第一个值的大小找到对应元素
特殊情况
- 不难想到当要去寻找a[k/2]和b[k/2]时可能造成数组越界问题,如果越界时,我们应该怎么办?
- 答:当数组越界时,我们应该选取数组的最后一个元素进行比较,但是会出现一个新的问题,这是我们所消去的元素个数就不是k/2了,我们需要根据排除树的个数减少k的值,而不能直接将k减去k/2
- 如果一个数组为空,则直接在另一个数组中寻找第k小的元素就可以