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

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。

public class Solution {
    public double findMedianSortedArrays(int A[], int B[]) {
        int n = A.length + B.length;
        // 两个数组长度加起来是偶数,找到中间两个数
        if (n % 2 == 0) {
            // 第(n / 2)个数
            int a = findKth(A, 0, B, 0, n / 2);
            // 第(n / 2 + 1)个数
            int b = findKth(A, 0, B, 0, n / 2 + 1);
            return (a + b) / 2.0;
        }
        // 两个数组长度加起来是奇数,找到第(n / 2 + 1)个数,就是中位数
        return findKth(A, 0, B, 0, n / 2 + 1);
    }

    /**
     * 返回两个数组中从小到大的第 k个数
     * @param A
     * @param startOfA A数组开始下标,用来表示删掉以后哪些数还是有效的
     * @param B
     * @param startOfB B数组开始下标,用来表示删掉以后哪些数还是有效的
     * @param k        AB数组合起来 C数组中的第几个数,注意不是下标
     * @return
     */
    public static int findKth(int[] A, int startOfA, int[] B, int startOfB, int k) {
        // A数组空了
        if (startOfA >= A.length) {
            // 返回 B的第k个数
            return B[startOfB + k - 1];
        }
        if (startOfB >= B.length) {
            return A[startOfA + k - 1];
        }
        if (k == 1) {
            return Math.min(A[startOfA], B[startOfB]);
        }
        // 找到 A、B数组中的第 k/2个数,在数组中下标就是k / 2 - 1
        // 当某一个数组没有 k/2 个之后,用最大值替代
        int halfKthOfA = startOfA + k / 2 - 1 < A.length ? A[startOfA + k / 2 - 1] : Integer.MAX_VALUE;
        int halfKthOfB = startOfB + k / 2 - 1 < B.length ? B[startOfB + k / 2 - 1] : Integer.MAX_VALUE;
        // 比较这两个数的大小
        if (halfKthOfA < halfKthOfB) {
            // 如果 A的第 k/2个位置比 B小,则丢掉 A前 k/2个,更新 A起始位置
            return findKth(A, startOfA + k / 2, B, startOfB, k - k / 2);
        } else {
            return findKth(A, startOfA, B, startOfB + k / 2, k - k / 2);
        }
    }
}

思路分析:
先看两个数组总数加起来是奇数还是偶数,如果是奇数则是合起来数组中(length = n)的第n/2+1个,如果是偶数则是中间两个数的平均数,中间两个数是合起来数组中的第n/2n/2+1
举个栗子

  • 当合起来数组长度是奇数时
arrA = [1,3,5,7] 
arrB = [2,4,6,8,10]
合起来后:
arrC = [1,2,3,4,5,6,7,8,10] // 5是中位数,是数组中的第 5(9/2+1)个数
  • 当合起来数组长度是偶数时
arrA = [1,3,5,7] 
arrB = [2,4,6,8]
合起来后:
arrC = [1,2,3,4,5,6,7,8] 
// 中位数:(4+5)/2.0=4.5,是数组中第 4(8/2)和第 5(8/2+1)个数的平均数

根据长度的奇偶性,转化为找两个数组合起来的第k个数

对于奇数的情况,要找第k = 5个数,比较A,B数组中第2(k / 2)个数的大小,第2个数的位置为k / 2 - 1 = 1
在这里插入图片描述
丢掉A数组的前两个数,然后在剩下的A和B中找第k = k - k / 2 = 3个数,比较A,B数组中第1(k / 2)个数的大小,第1个数的位置为k / 2 - 1 = 0

在这里插入图片描述
丢掉B数组的前一个数,然后在剩下的A和B中找第k = k - k / 2 = 2个数,比较A,B数组中第1(k / 2)个数的大小,第1个数的位置为k / 2 - 1 = 0
在这里插入图片描述
丢掉B数组的前一个数,然后在剩下的A和B中找第k = k - k / 2 = 1个数,比较A,B数组中第1(k / 2)个数的大小,第1个数的位置为k / 2 - 1 = 0

在这里插入图片描述
k = 1,直接返回 5
对于偶数的情况类似,只不过要找两个数而已

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值