查找两个有序数组的中位数和第K小的数

数组中查找中位数

1、将两个数组合合并并排序,查找中位数,时间复杂度为O((n+m)lg(m+n)),空间复杂度O(m+n)。

2、分别比较两个数组的K/2处的数,如果midA < midB,说明要查找的两个数在数组A的右半部分和数组B的左半部份。如果midA>midB,说明要查找的两个数在数组A的左半部分和数组B的右半部份。每次比较丢掉一半,时间复杂度为O(lg(m+n)),空间复杂度为O(1)。以上说的半部分指的是K个值的半部分。

public static double getMid(int []A,int []B){
        int l=(A.length+B.length+1)/2;
        int r=(A.length+B.length+2)/2;
        return (getMid(A,0,B,0,l)+getMid(A,0,B,0,r))/2.0;
    }

public static int getMid(int[]A,int startA,int[]B,int startB,int k){
        if(startA>A.length-1)return B[startB+k-1];
        if(startB>B.length-1)return A[startA+k-1];
        if(k==1)return Math.min(A[startA], B[startB]);
        int midA=Integer.MAX_VALUE;
        int midB=Integer.MAX_VALUE;
        if(startA+k/2-1<A.length)midA=A[startA+k/2-1];
        if(startB+k/2-1<B.length)midB=B[startB+k/2-1];
        if(midA<midB){
            //说明在A的右边的块,B的左边的块
            return getMid(A,startA+k/2,B,startB,k-k/2);
        }else if(midA>midB){
            //说明在A的左边的块,B的右边的块
            return getMid(A,startA,B,startB+k/2,k-k/2);
        }else{
            return midA;
        }
    }

数组中查找第K小的值
1、将两个数组合合并并排序,查找中位数,时间复杂度为O((n+m)lg(m+n)),空间复杂度O(m+n)。

2、分别比较两个数组的中位数,如果midA < midB且两个数组一半的长度和midVal小于等于K,说明要查找的数肯定不在B数组的右半部分。如果midA < midB且两个数组一半的长度和midVal大于K,说明要查找的数肯定不在A数组的左半部分。如果midA>midB且两个数组一半的长度和midVal小于等于K,说明要查找的数肯定不在A数组的右半部分。如果midA>midB且两个数组一半的长度和midVal大于K,说明要查找的数肯定不在B数组的左半部分。每次比较丢掉A的一半或者B的一半,时间复杂度大于O(lg(m+n))小于O(n),空间复杂度为O(1)。

public static int getKMin(int[] A, int[] B, int k) {
        return getKMin(A, 0, A.length - 1, B, 0, B.length, k);
    }
public static int getKMin(int[] A, int startA, int endA, int[] B,
            int startB, int endB, int k) {
        if (startA > endA)
            return B[startB + k - 1];
        if (startB > endB)
            return A[startA + k - 1];
        int midA = startA + (endA - startA) / 2;
        int midB = startB + (endB - startB) / 2;
        int midVal = midA - startA + midB - startB + 2;

        if (A[midA] <= B[midB]) {
            // 丢弃A的左半块
            if (midVal <= k) {
                return getKMin(A, midA + 1, endA, B, startB, endB, k
                        - (midA - startA + 1));
            } else {
                // 丢弃B的右半块
                return getKMin(A, startA, endA, B, startB, midB - 1, k);
            }
        } else {
            if (midVal <= k) {
                // 丢弃B的左半块
                return getKMin(A, startA, endA, B, midB + 1, endB, k
                        - (midB - startB + 1));
            } else {
                // 丢弃A的右半块
                return getKMin(A, startA, midA - 1, B, startB, endB, k);
            }

        }
    }

第一种方法每次丢弃A和B的K个值的一半,第二种方法每次丢掉A或B的一半,因此第一种方法比较好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值