leetcode求两个有序数组的中位数

有两个大小为 m 和 n 的排序数组 nums1 和 nums2 。

请找出两个排序数组的中位数并且总的运行时间复杂度为 O(log (m+n)) 。

示例 1:
在这里插入图片描述

这是问题,我刚开始刷leetCode还没多久,刚开始做这个题的时候,觉得真的挺难得。他的难点主要就是时间复杂度的问题。然后做了两三个小时实在做不出来我就找了看了官方给的解释,因为英语是个半吊子,理解起来蛮吃力的。查博客的话,大多只是写了个大概,对于我这个渣渣来说理解起来很吃力。所以我就想写一个更详细点的!

做这个题的时候我们要注意题目的意思:题目所给的两个数组已经排好序了,如果没注意到这点,这个题是没办法做。然后开始分析:

(1)本题的难点是要有了复杂度,也就是log(n+m) 看见log我们所能想到的肯定是用到了分冶法,不然不会出现这个玩意的。

(2)然后开始理解中位数,就是能把一个数组分成两半。也就是 左边的最大的数 小于等于 右边最小的数

接下来就可以了:暂时不考虑极端情况,假设数组A和数组B长度都大于2;

A: A[0] A[1] A[2]…A[m-3] A[m-2] A[m-1]

B: B[0] B[1] B[2]…B[n-3] B[n-2] B[n-1]

那么:分析一下, A和B的长度和起来是n+m,一般的长度就是 (n+m)/2

也就是 m/2 +n/2 那我们可以直接把 A和前半部分和B的前半部分 直接拿出来

A: A[0] A[1] A[2]… A[j-1] | A[j] …A[m-3] A[m-2] A[m-1] 将A分成了两半

B: B[0] B[1] B[2]… B[i-1] | B[i]…B[n-3] B[n-2] B[n-1] 将B分成了两半

A[j]是A的中位数,B[i]是B的中位数,这个中位数很好求的,(j=m/2 i=n/2)

然后我们将 A的前半部分和B的前半部分 合在一起,把A的后半部分和B的后半部分合在一起, 假如点半部分合起来的最大值 小于等于后半部分的最小值,那么中位数不是直接就求出了了么。用一个关系式表示:

j+i=(n+m)/2 && max(A[j-1] B[i-1]) <= min(A[j] B[i])

i和j是有关系的,这里不再讨论,看后面的关系式:要注意 A[j-1] 是一定小于 A[j]的(A和B是有序的)所以我们只需要让A[j-1] <=B[j] 就行,同理让 B[i-1] <= A[j] ,这样做的目的是什么呢?

因为实际情况肯定和我们想的不一样:

情况1:

A[j-1] > B[i] 了怎么办? 这时候我们可以理解为,A的左边有数据过大,所以我们必须把这个大数给 右边,但是这样就会产生左边的总数少了,那我们就把B右边的给左边一个就行了:

A: A[0] A[1] A[2]… A[j-2] | A[j-1] …A[m-3] A[m-2] A[m-1] j-1 | j+1

B: B[0] B[1] B[2]… B[i] | B[i+1]…B[n-3] B[n-2] B[n-1] i+1 | i-1

所以左边合起来的总是依旧等于右边合起来的总数:

同理:

B[i-1] > A[j] 就把 B[i-1]送给右边同时把A[i]送给左边就行。

A: A[0] A[1] A[2]… A[J] | A[j+1] …A[m-3] A[m-2] A[m-1] j+1 | j-1

B: B[0] B[1] B[2]… B[i-2] | B[i-1]…B[n-3] B[n-2] B[n-1] i-1 | i+1

没有第三种情况:

不可能两个条件同时不符合:因为 A[j]>= A[j-1] 如果 A[j-1] > B[i] 那么 A[j] >= A[j-1] > B[i] >=B[i-1] 所以A[j]>B[i-1]

当然如果n活着m是奇数的话,也不需要在意,因为我们要的是 ( max(left_part)+min(right_part) )/2

补充:我们是用 j来表示i的,所以m要小,为的是不让i算出了是个负数!!!

代码:

 public double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        if (m > n) { // to ensure m<=n
            int[] temp = A; A = B; B = temp;
            int tmp = m; m = n; n = tmp;
        }
        int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
        while (iMin <= iMax) {
            int i = (iMin + iMax) / 2;
            int j = halfLen - i;
            if (i < iMax && B[j-1] > A[i]){
                iMin = i + 1; // i is too small
            }
            else if (i > iMin && A[i-1] > B[j]) {
                iMax = i - 1; // i is too big
            }
            else { // i is perfect
                int maxLeft = 0;
                if (i == 0) { maxLeft = B[j-1]; }
                else if (j == 0) { maxLeft = A[i-1]; }
                else { maxLeft = Math.max(A[i-1], B[j-1]); }
                if ( (m + n) % 2 == 1 ) { return maxLeft; }

                int minRight = 0;
                if (i == m) { minRight = B[j]; }
                else if (j == n) { minRight = A[i]; }
                else { minRight = Math.min(B[j], A[i]); }

                return (maxLeft + minRight) / 2.0;
            }
        }
        return 0.0;
    }


    public static void main(String[] args) {
        int a[] = {1,2,3};
        int b[] = {4,5,6,7};
        Soultion soultion = new Soultion();
        System.out.println(soultion.findMedianSortedArrays(a,b));

    }
}

中位数:4.0


作者:qq_41014682
来源:CSDN
原文:https://blog.csdn.net/qq_41014682/article/details/79812181
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值