Median of Two Sorted Arrays

0x00

难度:Hard

There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

You may assume nums1 and nums2 cannot be both empty.

Example 1:

nums1 = [1, 3]
nums2 = [2]

The median is 2.0
Example 2:

nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5

题目的意思是寻找中位数的平均值。题目的前提条件有问题,会对解题造成一定困扰,时间复杂度应该是 O(log(min(m,n))),不是 O(log(m+n))。

0x01

先说思路

  1. 找中位数可以转换成另一个命题,找一个数,其下标等于中位数的下标,也就是说这道题目可以转换成在整体数组中找某个Index的数。
  2. 假设存在两个单调递增的子数组 num1 与 num2。
  3. .假设我们需要找的数的下标为idx。我们判断num1中下标为num1Idx的数是否为整体数组中下标为idx的数,需要满足这个条件:num2[idx - num1Idx - 1] <= num1[num1Idx] <= num2[idx-num1Idx]。如果这个条件满足,那么num[num1Idx]恰好就是整体数组中下标为idx的数。
  4. 同理,如果满足num1[num1Idx] <= num2[idx - num1Idx - 1] <= num1[num1Idx+1],就说明 num2[idx - num1Idx - 1]为整体数组中下标为idx的数。
  5. 那么我们就需要遍历num1,来判断是否满足这个条件。但是这个遍历也是有技巧的。我们取num1[num1Idx](n)与num2[idx - num1Idx - 1](m)比较大小。如果 n >= m,那么判断下步骤3是否满足,如果满足,遍历结束;如果不满足,我们就需要向下遍历num1。同理,如果n<=m,判断步骤4是否满足,如果不满足,我们就需要向上遍历num1。如此我们可以使用二分查找快速遍历。
  6. 我们在步骤3与4中,使用到了 idx - num1Idx - 1,这里就必须保证 idx - num1Idx - 1 >= 0。也就是idx >= num1Idx +1。因为使用二分查找,所以num1Idx=len(num1)/2。而查找中位数的话,idx=(len(num1)+len(num2))/2,因此就存在 len(num1)<=len(num2),也就是时间复杂度为 O(log(min(m,n)))。

0x02

我的代码如下:

func checkMatch(num1,num2 []int,num1Idx int,idx int) (ret,valueGot int) {
	if idx > len(num2) {
		ret = 1
		return//upper
	}
	if num2[idx] >= num1[num1Idx] {
		//num1[num1Idx] <= num2[idx] <= num1[num1Idx+1]
		if (num1Idx == len(num1) - 1) || (num2[idx] <= num1[num1Idx+1]) {
			ret = 0
			valueGot = num2[idx]
			return
		}

		ret = 1
		return
	}
	if num2[idx] <= num1[num1Idx]{
		//num2[idx] <= num1[num1Idx] <= num2[idx+1]
		if (idx == len(num2) - 1) || (num1[num1Idx] <= num2[idx+1]) {
			ret = 0
			valueGot = num1[num1Idx]
			return
		}
		ret = -1
		return
	}
	return
}


func locateValueByIdx(num1 ,num2 []int,idx int) int {
	if 0 == len(num1) {
		return  num2[idx]
	} else if 0 == len(num2) {
		return num1[idx]
	} else if 0 == idx {
		if num1[0] > num2[0] {
			return num2[0]
		}
		return num1[0]
	}
	if len(num2) > len(num1) {
		num1,num2 = num2,num1
	}
	lIdx,hIdx := 0,len(num1) - 1
	for {
		midIdx := (lIdx + hIdx) / 2
		if (midIdx + 1 > idx) || (idx - midIdx - 1 >= len(num2)) {
			num1,num2 = num2,num1
			lIdx,hIdx = 0,len(num1) - 1
			continue
		}
		ret,valueGot := checkMatch(num1,num2,midIdx,idx - midIdx - 1)

		if 0 == ret {
			return valueGot
		}
		if 1 == ret {
			lIdx = midIdx + 1
		} else {
			hIdx = midIdx - 1
		}
		if lIdx > hIdx {
			return num2[idx]
		}
	}
}

func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
	numLen := len(nums1) + len(nums2)
	idx := numLen / 2
	val1 := float64(locateValueByIdx(nums1,nums2,idx))
	if numLen % 2 == 1 {
		return val1
	}
	val2 := float64(locateValueByIdx(nums1,nums2,idx - 1))

	return (val1 + val2) / 2
}

solution的代码如下:

class Solution {
    public double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        if (m > n) { // to ensure m<=n
            int[] temp = A; A = B; B = temp;
            int tmp = m; m = n; n = tmp;
        }
        int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
        while (iMin <= iMax) {
            int i = (iMin + iMax) / 2;
            int j = halfLen - i;
            if (i < iMax && B[j-1] > A[i]){
                iMin = i + 1; // i is too small
            }
            else if (i > iMin && A[i-1] > B[j]) {
                iMax = i - 1; // i is too big
            }
            else { // i is perfect
                int maxLeft = 0;
                if (i == 0) { maxLeft = B[j-1]; }
                else if (j == 0) { maxLeft = A[i-1]; }
                else { maxLeft = Math.max(A[i-1], B[j-1]); }
                if ( (m + n) % 2 == 1 ) { return maxLeft; }

                int minRight = 0;
                if (i == m) { minRight = B[j]; }
                else if (j == n) { minRight = A[i]; }
                else { minRight = Math.min(B[j], A[i]); }

                return (maxLeft + minRight) / 2.0;
            }
        }
        return 0.0;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值