寻找两个排序数组(长度相等)的上中位数

算法专题导航页面


【算法专题 - 应用场景】

  1. 数字游戏 – 寻找缺失的数字
  2. 数字游戏 – 微信红包
  3. 寻找两个排序数组(长度相等)的上中位数

【题目】
  现有两个长度相等的排序数组(升序),求这两个排序数组组成的新数组的中位数。

【其他限制】
  时间复杂度最好为O(nlogn),空间复杂度为O(1)。

【图示】
  假设两个排序数组为arr1和arr2,长度均为N,则这两个数组的上中位数为这2N个数中的第N个数
  下面两个图片分别对应N为奇数和偶数时,两个数组的上中位数的取值情况:
在这里插入图片描述
上述两个数组{1, 6, 7}和{2, 4, 6}的上中位数为这6个数中第3小的数,其值为4.
在这里插入图片描述
上述两个数组{1, 6, 7, 11}和{2, 4, 6, 8}的上中位数为这8个数中第4小的数,其值为6.
请留意,当N为偶数时,中间位置数值较小的那个数组在更新查询范围时候的规律:新查询范围的起始索引是中间位置+偏移量1


【分析】
  依据限定的时间复杂度O(nlogn)可知,应该考虑如何采用二分查找法来寻找上中位数。
  二分查找算法的思想在于通过不断缩小问题的规模,也即元素的查找范围,来提升算法的执行效率。
  此处我们假定arr1[start1, …, end1],arr2[start2, …, end2]分别代表两个排序数组,初始状态下start1=start2=0, end1=end2=N-1。mid1=(start1+end1)/2, mid2=(start2+end2)/2, arr2[mid2]分别代表数组arr1, arr2的中间位置。依据数组长度N与1的关系,我们可以分三个类别对该问题进行描述:

  • N小于1
    无效长度!数组的长度只可能大于等于1.
  • N 等于 1
    此种情况下,每个数组仅有一个元素,故两个数组的上中位数即为最小的那个元素,也即min(arr1[N-1], arr2[N-1])。
  • N > 1,此时我们需要依据arr1[mid1]和arr2[mid2]的大小关系不断缩小上中位数的查询范围
    1. arr1[mid1] = arr2[mid2]
        此时,两个数组的上中位数即为arr1[mid1]或者arr2[mid2].
        因为在数组arr1中,位置mid1或mid2前有(start1+end1)/2个元素;在数组arr2中,位置mid1或mid2前有(start2+end2)/2个元素。故mid或mid2必然是两个数组中的第N个数。
    2. arr1[mid1] > arr2[mid2]
        此时,两个数组的上中位数只可能存在于由数组arr1[start1, mid1)和arr2[mid2+1, end2]构成的数组中,原因详见如下分析:
        既然我们采用的是二分查找的策略,且mid1和mid2对应位置元素都不是组合数组的上中位数。那么真正的上中位数的查找范围必然和mid1以及mid2有密切联系。为了找出相应的联系,我们做出以下两种假设:
        2.1 第一种假设:arr1[mid1]是上中位数
        因为在数组arr1中,位置mid1前有(start1+end1)/2个元素;在数组arr2中,因为mid1>mid2,故arr1[mid1]至少大于数组的前(start2+end2)/2 + 1个元素,也即mid1至少是两个数组中第N+1个元素。这一点证明了组合数组的上中位数只可能存在于数组arr1的前半部分arr1[start1, mid1)。
        2.2 第二种假设:arr2[mid2]是上中位数
        因为在数组arr2中,位置mid2前有(start2+end2)/2个元素;在数组arr1中,因为mid1>mid2,故arr2[mid2]至多大于数组的前(start1+end1)/2个元素,也即mid2至多是两个数组中第N个元素。既然arr2[mid2]可能是组合数组的上中位数,那么我们需要进一步搞清楚何时其可能成为组合数组的中位数。为了理清楚这一点,我们增加N的奇偶性的判定。
            2.2.1 当N为偶数的时候,如[图示]部分第二幅图,此时组合数组的上中位数只可能存在于数组arr2的后半部分arr2[mid2, end2]。
            2.2.1 当N为奇数的时候,如[图示]部分第一幅图,此时组合数组的上中位数只可能存在于数组arr2的后半部分arr2[mid2+1, end2]
    3. arr1[mid1] < arr2[mid2]
        此时,两个数组的上中位数只可能存在于由数组arr1[mid1+1, end1]和arr2[start2, mid2]构成的数组中,具体分析可参照情况2,此处不再赘述。

【代码实现】

public int getUpMedian(int[] arr1, int[] arr2) {
    if (null == arr1 || null == arr2 || arr1.length != arr2.length) {
        throw new RuntimeException("Invalid input arry!");
    }
    
    int start1 = 0;
    int end1 = arr1.length -1;
    int start2 = 0;
    int end2 = arr2.length - 1;
    int mid1 = 0;
    int mid2 = 0;
    int offset = 0;
    while (start1 < end1) {
        mid1 = (start1 + end1)/2;
        mid2 = (start2 + end2)/2;
        // 数组长度为奇数时,offset=0;数组长度为偶数时,offset=1
        offset = ((end1-start1 + 1) & 1) ^ 1; // 数组的长度在不断缩减
        if (arr1[mid1] > arr2[mid2]) {
            end1 = mid1;
            start2 = mid2 + offset;
        } else if () {
            start1 = mid1 + offset;
            end2 = mid2;
        } else {
			return arr1[mid1];
		}
    }
	
	return Math.min(arr1[start1], arr2[start2]); // 数组长度为1时,直接返回组合数组的最小元素
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值