思路及难点
寻找数组中第k小的数字
在寻找第k小的数字时,每次删除k/2个数字,即下一次寻找第k/2个数字。将时间复杂度降低至O(log(k))。对于中位数来说,k=(m+n)/2,因此将时间复杂度降低到O(log(m+n))。
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
int k = (m+n) / 2;
int kth = getKthEle(nums1, nums2, k + 1);
if ((m+n) % 2 != 0)
return kth;
return (getKthEle(nums1, nums2, k) + kth) / 2.0;
}
public static int getKthEle(int[] nums1, int[] nums2, int k)
{
int m = nums1.length;
int n = nums2.length;
int ret = Integer.MAX_VALUE;
if (m + n >= k) // 第k个元素必须在数组中
{
int i = 0, j = 0, half; // pos of nums1, pos of nums2, half of k pos
int ii = i, jj = j; // reserve the old value
while (true)
{
half = k/2 - 1;
ii = i;
jj = j;
if (ii == m)
return nums2[jj+k-1];
if (jj == n)
return nums1[ii+k-1];
if (k == 1)
return nums1[ii] < nums2[jj] ? nums1[ii] : nums2[jj];
i = i+half < m-1 ? i+half : m-1;
j = j+half < n-1 ? j+half : n-1;
boolean flag = false; //并非是末端情况
if (nums1[i] <= nums2[j])
{
if (i == m-1)
flag = true;
i++; //表示数组i之前的数字都可以舍弃了
j = jj; //回退到起始位置
}
else if (nums1[i] > nums2[j])
{
if (j == n-1)
flag = true;
j++;
i = ii;
}
int min = half+1;
//舍弃整个数组的条件是:i=m-1,且nums1[i] < nums2[j],否则舍弃一半
if (flag)
min = min < Math.min(m, n) ? min : Math.min(m, n);
// 应该舍弃一半的数据还是舍弃掉整个数组?
k = k - min;
}
}
return ret;
}