天天看點

找到兩個排序數組的中位數以及第k大的數

public class Main {
    public static void main(String[] args) {
        int[] a = new int[] {2,4};
        int[] b = new int[] {1,3,5};
        
        //找到第3大的數字
        System.out.println(findKK(a, b, 3));
        
        //找到中位數
        System.out.println(findMid(a, b));
    }

    // 找到第k個
    public static int findKK(int[] a, int[] b, int k) {
        if(k == 0) {
            return Math.min(a[0], b[0]);
        }
        return supFindKK(a, 0, a.length, b, 0, b.length, k);
    }

    public static int supFindKK(int[] a, int l1, int r1, int[] b, int l2, int r2, int num) {
        if(num == 1) {
            return Math.min(a[l1], b[l2]);
        }
        int ka = Math.min(num / 2, r1 - l1 + 1);
        int kb = Math.min(num - ka, r2 - l2 + 1);
        if(a[l1 + ka - 1] > b[l2 + kb - 1]) {
            return supFindKK(a, l1, l1 + ka - 1, b, l2 + kb, r2, num - kb);
        } else {
            return supFindKK(a, l1 + ka, r1, b, l2, l2 + kb - 1, num - ka);
        }

    }

    //找到中位數
    public static double findMid(int[] a, int[] b) {
        if(a.length > b.length) return findMid(b, a);
        int n = a.length;
        int m = b.length;
        int l1 = 0, l2 = 0, r1 = 0, r2 = 0, c1, c2, lo = 0, hi = 2 * n;
        while(lo <= hi) {
            c1 = (lo + hi) / 2;
            c2 = m + n - c1;
            l1 = (c1 == 0) ? Integer.MIN_VALUE : a[(c1 - 1) / 2];
            r1 = (c1 == 2 * n) ? Integer.MAX_VALUE: a[c1 / 2];
            l2 = (c2 == 0) ? Integer.MIN_VALUE : b[(c2 - 1) / 2];
            r2 = (c2 == 2 * m) ? Integer.MAX_VALUE : b[c2 / 2];

            if(l1 > r2) {
                hi = c1 - 1;
            } else if(l2 > r1) {
                lo = c1 + 1;
            } else break;
        }
        return (Math.max(l1, l2) + Math.min(r1, r2)) / 2.0;
    }
}