力扣 Top100 4. 寻找两个正序数组的中位数

题目来源:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/

大致题意:
给两个升序数组,找出两个数组元素合并后的中位数

思路

这道题等价于求两个数组中第 k 小的数

题目要求 log(m + n) 的复杂度,所以可以用二分

每次比较两个数组第 k/2 个数的大小,将小的元素所在数组的前 k/2 个元素去掉(因为第 k 小的数一定不会在这部分),这样每次去一半,直到有个数组的元素全部去掉或者 k 为 1

为什么较两个数组第 k/2 个数的大小时可以将小的元素所在数组的前 k/2 个元素去掉?

  • 假设有数组 A 和 B,若 A[k/2 - 1] 小于 B[k/2 - 1],那么小于 A[k/2] 的元素最多有 A[0] - A[k/2 - 2] 和 B[0] - B[k/2 - 2] 共 k - 2 个元素,即 A[k/2] 一定不是第 k 小的数,所以 A[0] - A[k/2 - 1] 都可以去掉

具体实现时,要注意到遍历索引不能越界,去掉的数组元素应为实际值

public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        double ans = 0.0;
        int k = (m + n) / 2;
        // 两个数组合并长度为奇数
        if ((m + n) % 2 == 1) {
            ans = getKthElement(nums1, nums2, k + 1);
        } else {
            // 两个数组合并长度为偶数
            ans = (getKthElement(nums1, nums2, k) + getKthElement(nums1, nums2, k + 1)) / 2.0;
        }

        return ans;
    }

    public int getKthElement(int[] nums1, int[] nums2, int k) {
        int idx1 = 0;   // 数组 1 的索引
        int idx2 = 0;   // 数组 2 的索引
        int len1 = nums1.length;
        int len2 = nums2.length;
        while (true) {
            // 若有一个数组元素已经全部去掉,直接从另一个中取答案
            if (idx1 == len1) {
                return nums2[idx2 + k - 1];
            }
            if (idx2 == len2) {
                return nums1[idx1 + k - 1];
            }
            // 若 k 为 1,则取当前两个数组还未去掉元素中的最小值
            if (k == 1) {
                return Math.min(nums1[idx1], nums2[idx2]);
            }
            // 数组目前第 k/2 小的索引
            int newIdx1 = Math.min(idx1 + k / 2, len1) - 1;
            int newIdx2 = Math.min(idx2 + k / 2, len2) - 1;
            // 选择去掉的索引
            if (nums1[newIdx1] <= nums2[newIdx2]) {
                // 更新 k
                k -= newIdx1 - idx1 + 1;
                idx1 = newIdx1 + 1;
            } else {
                k -= newIdx2 - idx2 + 1;
                idx2 = newIdx2 + 1;
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值