LeetCode(4) Median of Two Sorted Arrays解题报告

求两个有序数组的中位数

问题:

There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n))

大意:

有两个有序的数组nums1和nums2,他们的长度分别为m和n。求两个数组的中位数。时间复杂度为O(log(m + n))

示例:

Example 1:
nums1 = [1, 3]
nums2 = [2]

The median is 2.0

Example 2:
nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5

解题方案:

    看到这道题,很容易想到的思路就是用归并,将两个数组按照顺序归并的过程中很容易求出中位数。但是这道题的难点就是如何在O(log(m + n))的时间复杂度内求出结果。
    在O(log n)的时间复杂度内易想到通过2分查找或者分治的思想来解决。
    我们可以这样考虑,对于两个数组nums1和nums2,如果m + n是偶数,那么中位数就是nums1和nums2数组合并之后的第(m + n)/2 和 (m + n)/2 + 1 个数的和平均数;如果 m + n是奇数,那么中位数就是(m + n)/2 + 1。所以我们可以将问题一般化,即求合并后的两个素组的第k个数。
    令 a + b = k - 1,其中 a是nums1中的第a个数,b是nums2中的第b个数,那么只需要比较nums1[a + 1] 和 nums[b + 1]即可求得第k个数。那么问题的关键就是如何确定a和b的大小。
    初始我们令 a = min(k/2, m),b = k - 1 - b (这里我们假设m < n总是成立,假如nums1过小,那么第k个数必在nums2中。) 这里有以下几种情况:  
    1.  k = 1,则sums[a + 1]和sums2[b + 1]中较小的即为所求。
    2. sums1[a] < sums2[b],则将sums1中前a个数删除,并令k = k - a,并重新计算a和b。
    3. sums1[a] > sums2[b],则将sums2中前b个数删除,并令k = k - b,并重新计算a和b。 
    4. sums1[a] = sums2[b],则sums1[a + 1]和sums2[b + 1]中较小的即为所求。

    代码如下:
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int len1 = nums1.length;
        int len2 = nums2.length;

        int k = (len1 + len2) / 2;
        if ((len1 + len2) % 2 == 0) {
            return (double)(findKth(nums1, nums2, 0, 0, len1, len2, k) + findKth(nums1, nums2, 0, 0, len1, len2, k + 1)) / 2;
        } else {
            return findKth(nums1, nums2, 0, 0, len1, len2, k + 1);
        }

    }

    private int findKth(int[] nums1, int[] nums2, int start1, int start2, int len1, int len2, int k) {
        if (len1 > len2) {
            //确保len1 < len2
            return findKth(nums2, nums1, start2, start1, len2, len1, k);
        }
        if (len1 == 0) {
            return nums2[start2 + k - 1];
        }
        if (k == 1) {
            return Math.min(nums1[start1], nums2[start2]);
        }

        int p1 = Math.min(k/2, len1);
        int p2 = k - p1;
        if (nums1[start1 + p1 - 1] < nums2[start2 + p2 - 1]) {
            return findKth(nums1, nums2, start1 + p1, start2, len1 - p1, len2, k - p1);
        } else if (nums1[start1 + p1 - 1] > nums2[start2 + p2 - 1]) {
            return findKth(nums1, nums2, start1, start2 + p2, len1, len2 - p2, k - p2);
        } else {
            return nums1[start1 + p1 - 1];
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值