寻找两个正序数组的中位数

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。

请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

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

则中位数是 2.0
示例 2:

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

则中位数是 (2 + 3)/2 = 2.5
解法:
public class Solution {

    public static void main(String[] args) {

       
        Solution solution = new Solution();

        int len1 = 10000000;
        int len2 = 10000000;
        int[] arr1 = new int[len1];
        int[] arr2 = new int[len2];
        int idx1 = 0;
        int idx2 = 0;
        Random random = new Random();
        for (int i = 0; i < len1 + len2; i++) {
            int rand = 100 + random.nextInt(100);
            if (random.nextInt(10) / 10 < 1) {
                if (idx1 < len1) {
                    arr1[idx1] = idx1 == 0 ? 10000 : arr1[idx1 - 1] + rand;
                    idx1++;
                } else if (idx2 < len2) {
                    arr2[idx2] = idx2 == 0 ? rand : arr2[idx2 - 1] + rand;
                    idx2++;
                }
            } else {
                if (idx2 < len2) {
                    arr2[idx2] = idx2 == 0 ? rand : arr2[idx2 - 1] + rand;
                    idx2++;
                } else if (idx1 < len1) {
                    arr1[idx1] = idx1 == 0 ? 10000 : arr1[idx1 - 1] + rand;
                    idx1++;
                }
            }
        }

        long start = System.currentTimeMillis();

        double result = solution.findMedianSortedArrays(arr1, arr2);

        System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms, 结果为:" + result);

        long start2 = System.currentTimeMillis();
        double result2 = solution.findMedianSortedArrays2(arr1, arr2);
        System.out.println("耗时:" + (System.currentTimeMillis() -start2 ) + "ms, 结果为:" + result2);
    }

    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int num2Len = nums2.length;
        int num1Len = nums1.length;
        if (num1Len > num2Len) {
            return findMedianSortedArrays(nums2, nums1);
        }
        if (num1Len == 0) {
            return findMid(nums2, 0, num2Len);
        }
        return split(nums1, nums2, 0, num1Len, 0, num2Len);
    }

    private double merge(int[] nums1, int[] nums2, int nums1Left, int nums1Offset, int nums2Left, int nums2Offset) {
               int nums1RightIdx = nums1Left + nums1Offset - 1;
        int nums2RightIdx = nums2Left + nums2Offset - 1;
        int[] temp = new int[nums1Offset + nums2Offset];
        int idxTemp = 0;
        while (true) {
            if (nums1Left > nums1RightIdx && nums2Left > nums2RightIdx) {
                break;
            }
            if (nums1Left > nums1RightIdx && nums2Left <= nums2RightIdx) {
                temp[idxTemp++] = nums2[nums2Left++];
            }
            if (nums1Left <= nums1RightIdx && nums2Left > nums2RightIdx) {
                temp[idxTemp++] = nums1[nums1Left++];
            }
            if (nums1Left <= nums1RightIdx && nums2Left <= nums2RightIdx) {
                temp[idxTemp++] = nums1[nums1Left] < nums2[nums2Left] ? nums1[nums1Left++] : nums2[nums2Left++];
            }
        }
        return findMid(temp, 0, temp.length);
    }

    private double split(int[] nums1, int[] nums2, int nums1Left, int nums1Right, int nums2Left, int nums2Right) {
        int num1Len = nums1Right - nums1Left;
        int num2Len = nums2Right - nums2Left;
        if (num1Len <= 7 && num2Len <= 7) {
            return merge(nums1, nums2, nums1Left, num1Len, nums2Left, num2Len);
        }
        if (nums1[nums1Right - 1] < nums2[nums2Left]) {// nums1 最大 < nums 2的最小
            return findMid(nums2, nums2Left, nums2Right - num1Len);
        }
        if (nums2[nums2Right - 1] < nums1[nums1Left]) {// nums2 最大 < nums的最小
            return findMid(nums2, nums1Left + num1Len, nums2Right);
        }
        if (num1Len <= 3 && num2Len > 7) {
            //中间向左偏2的位置
            int start = Math.max(nums2Left + (num2Len / 2 - 2), 0);
            return split(nums1, nums2, nums1Left, nums1Right, start, num2Len % 2 == 0 ? start + 4 : start + 5);
        }
        double mid1 = findMid(nums1, nums1Left, nums1Right);
        double mid2 = findMid(nums2, nums2Left, nums2Right);
        int cutOff = num1Len / 2 - 1;
        if (mid1 < mid2) {
            return split(nums1, nums2, nums1Left + cutOff, nums1Right, nums2Left, nums2Right - cutOff);
        }
        if (mid1 > mid2) {
            return split(nums1, nums2, nums1Left, nums1Right - cutOff, nums2Left + cutOff, nums2Right);
        }
        return mid1;
    }

    private double findMid(int[] nums, int nums1Left, int nums1Right) {
        int len = nums1Right - nums1Left;
        if (len <= 0)
            return -1;
        if (len % 2 == 0) {//偶数
            return (nums[nums1Left + len / 2 - 1] + nums[nums1Left + len / 2]) / 2.0;
        } else {//奇数
            return nums[nums1Left + len / 2];
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值