欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-23 17:32:07
...

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都是有序的,我们应该充分利用这里面的信息,类似于二分查找,也是充分利用了“有序”。

详细思路:

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

参考代码:
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));
    }
}