在两个排序数组中找到第k小的数

注:该系列博客主要用于记录学习左程云老师的算法最优解,感兴趣的同学可以看一下《程序员代码面试指南》一书

题目:

给定两个有序数组arr1和arr2,再给定一个整数k,返回所有的数中第k小的数。

举例:

arr1=[1,2,3,4,5],arr2=[3,4,5],k=1。

1是所有数中第1小的数,所以返回1。

arr1=[1,2,3],arr2=[3,4,5,6],k=4。

3是所有数中第4小的数,所以返回3。

要求:

如果arr1的长度是N,arr2的长度是M,时间复杂度请达到O(log(min{M,N})),额外空间复杂度为O(1)。

tip:这道题用到了题目“在两个长度相等的排序数组中找到上中位数”的算法,详细请看博主关于这一题的博客

/**
 * Created by Engin on 2017-03-10.
 * 题目:P468
 * 在两个排序数组中找到第K小的数
 */
public class P468 {
    public static int [] arr1 = {1, 2, 3, 4, 5, 6, 7, 55, 56, 57, 58, 59, 60};
    public static int [] arr2 = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
            20, 21, 22, 23, 24, 25, 26, 50, 51, 52, 53, 54};
    public static final int k = 15;// 7 15 33
    public static void main(String[] args) {
        System.out.println(getResult(arr1, arr2, k));
    }

    public static int getResult(int [] arr1, int [] arr2, int k){
        if(arr1 == null || arr2 == null){
            return -1;
        }
        if(k < 1 || k > arr1.length + arr2.length){
            return -1;
        }
        int [] shortArr = arr1.length < arr2.length ? arr1 : arr2;
        int [] longArr = arr1.length >= arr2.length ? arr1 : arr2;
        int s = shortArr.length;
        int l = longArr.length;
        if(k <= s){
            return getUpMedian(shortArr, 0, k-1, longArr, 0, k-1);
        }
        if(k > l){
            if(shortArr[k - l - 1] >= longArr[l - 1]){
                return shortArr[k - l - 1];
            }
            if(longArr[k - s - 1] >= shortArr[s - 1]){
                return longArr[k - s - 1];
            }
            return getUpMedian(shortArr, k - l, s - 1, longArr, k - s, l - 1);
        }
        if(longArr[k - s - 1] >= shortArr[s - 1]){
            return longArr[k - s - 1];
        }
        return getUpMedian(shortArr, 0, s - 1, longArr, k - s, k - 1);
    }

    public static int getUpMedian(int [] arr1, int start1, int end1, int [] arr2, int start2, int end2){
        int mid1 = 0;
        int mid2 = 0;
        int offset = 0;
        while(start1 < end1){
            mid1 = (start1 + end1) / 2;
            mid2 = (start2 + end2) / 2;
            offset = ((end1 - start1 + 1) & 1) ^ 1;
            if(arr1[mid1] > arr2[mid2]){
                end1 = mid1;
                start2 = mid2 + offset;
            }else if(arr1[mid1] < arr2[mid2]){
                start1 = mid1 + offset;
                end2 = mid2;
            }else{
                return arr1[mid1];
            }
        }

        return Math.min(arr1[start1], arr2[start2]);
    }
}





你可能感兴趣的:(算法题最优解,算法,java)