LeetCode------Madian of Two Sorted Arrays

这里写图片描述

这是一道非常经典的题。这题更通用的形式是,给定两个已经排序好的数组,找到两者所有元素中第 k 大的元素,只不过这道题是求中位数。

解法一

直接合并两个数组,然后求第 k 大的元素,O(m+n) 的解法比较直观。

解法二

我们仅仅需要第 k 大的元素,是不需要“排序”这么昂贵的操作的。可以用一个计数器,记录当前已经找到第m大的元素了。同时我们使用两个指针 pA 和 pB ,分别指向A和B数组的第一个元素,还是合并数组的原理,如果数组A当前元素小,那么 pA++ ,同时m++ ;如果数组B当前元素小,那么 pB++ ,同时 m++ 。最终当 m 等于 k 的时候,就得到了我们的答案,O(k) 时间, O(1) 空间。但是,当 k 很接近 m+n 的时候,这个方法还是 O(m+n) 的。

解法三

有没有更好的方案呢?我们可以考虑从 k 入手。如果我们每次都能够删除一个一定在第 k 大元素之前的元素,那么我们需要进行 k 次。但是如果每次我们都删除一半呢?由于A和B都是有序的,我们应该充分利用这里面的信息,类似于二分查找,也是充分利用了“有序”。

详细思路:

这里写图片描述

参考代码:
package com.zhumq.lianxi;

import org.junit.Test;

public class MadianofTowSortedArrays {
    public double findMedianSortedArrays(final int[] arr1,final int[] arr2) {
        int total = arr1.length + arr2.length;
        if(total%2 == 1) {
            //总长度为奇数时,中位数直接为中间的那个数
            return findKth(arr1,0,arr2,0,total/2+1);
        }else {
            //总长度为偶数时,中位数为最中间两个数的平均数
            return (findKth(arr1,0,arr2,0,total/2)+findKth(arr1,0,arr2,0,total/2+1))/2.0;
        }
    }

    //ai为A数组起始索引,bi为B数组起始索引
    private int findKth(int[] A, int ai, int[] B, int bi, int k) {
        //总是假定让A指向长度短的那个数组,统一操作
        if(A.length-ai>B.length-bi) {
            //A长度比B大时交换位置
            return findKth(B,bi,A,ai,k);
        }
        //A的长度为0时直接返回B数组的中位数即可
        if(A.length - ai == 0) return B[bi+k-1];
        //当k=1时返回A、B数组最小值
        if(k==1) return Math.min(A[ai], B[bi]);

        //

        /*
         * 将k分为两部分:
         *      A数组长度小于k/2,这时候k1取A的整个长度,而k2取k剩余部分的长度即k-k1
         *      A数据长度大于等于k/2时,k1和k2两部分长度都为k/2
         */
        int k1 = Math.min(k/2, A.length-ai);
        int k2 = k - k1;
        if (A[ai + k1 - 1] < B[bi + k2 - 1])
            //如果A中k1部分末尾元素小于B中k2部分末尾元素则可以去掉A中k1部分
            return findKth(A, ai + k1, B, bi, k - k1);
        else if (A[ai + k1 - 1] > B[bi + k2 - 1])
            //如果A中k1部分末尾元素大于等于B中k2部分末尾元素则可以去掉B中k2部分
            return findKth(A, ai, B, bi + k2, k - k2);
        else
            //相等的话就直接为两部分的最末元素
            return A[ai + k1 - 1];
    }

    @Test
    public void test1() {
        int arr1[] = {1,2,3,4,5};
        int arr2[] = {2,2,3,4,6};
        System.out.println(findMedianSortedArrays(arr1, arr2));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值