算法(二):寻找两个正序数组的中位数

题目

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

理解

时间复杂度为O(log(m+n)),基本是二分查找,如果不考虑时间复杂度的情况下,可以用归并排序,先合并成有序数组,然后计算中位数轻而易举。怎么理解二分查找?

  • 首先选择数组中间的数字和需要查找的目标值比较

  • 如果相等最好,就可以直接返回答案了

  • 如果不相等

  • 如果中间的数字大于目标值,则中间数字向右的所有数字都大于目标值,全部排除

  • 如果中间的数字小于目标值,则中间数字向左的所有数字都小于目标值,全部排除

    注意的点是:

  • while循环中 left 和 right 的关系,到底是 left <= right 还是 left < right

  • 迭代过程中 middle 和 right 的关系,到底是 right = middle - 1 还是 right = middle

题目

我们可以把两个数组分为左右两个部分
算法(二):寻找两个正序数组的中位数_第1张图片

1.当 A 数组和 B 数组的总长度是偶数时

  • 左右部分长度相同
  • 左部分最大值小于右部分最小值
    则中位数的值是两者平均数

2.当总长度是奇数

  • 左部分比右部分大1
  • 左部分最大值小于右部分最小值
    则中位数是左部分最大值

为了保证 max ( A [ i - 1 ] , B [ j - 1 ])) <= min ( A [ i ] , B [ j ])),因为 A 数组和 B 数组是有序的,所以 A [ i - 1 ] <= A [ i ],B [ i - 1 ] <= B [ i ] 这是天然的,所以我们只需要保证 B [ j - 1 ] < = A [ i ] 和 A [ i - 1 ] <= B [ j ] 所以我们分两种情况讨论:

  • B [ j - 1 ] > A [ i ]
    我们需要增加 i ,为了数量的平衡还要减少 j ,幸运的是 j = ( m + n + 1) / 2 - i,i 增大,j 自然会减少。

  • A [ i - 1 ] > B [ j ]
    我们要减少 i ,增大 j 。
    上边两种情况,我们把边界都排除了,需要单独讨论。

  • 当 i = 0, 或者 j = 0,也就是切在了最前边。
    当 j = 0 时,最大的值就是 A [ i - 1 ] ;当 i = 0 时 最大的值就是 B [ j - 1] 。右半部分最小值和之前一样。

  • 当 i = m 或者 j = n,也就是切在了最后边。
    此时左半部分最大值和之前一样。右半部分当 j = n 时,最小值就是 A [ i ] ;当 i = m 时,最小值就是B [ j ] 。

上边的第一个条件我们其实可以合并为 j=(m+n+1)/2−ij = ( m + n + 1) / 2 - ij=(m+n+1)/2−i,因为如果 m+nm + nm+n 是偶数,由于我们取的是 intintint 值,所以加 111 也不会影响结果

流程图

算法(二):寻找两个正序数组的中位数_第2张图片

代码

class Solution(object):
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        m, n = len(nums1), len(nums2)
        if m > n:
            nums1, nums2, m, n = nums2, nums1, n, m
        
        imin, imax, half_len = 0, m, (m + n + 1) // 2
        
        while imin <= imax:
            i = (imin + imax) // 2
            j = half_len - i
            
            if i < m and nums2[j-1] > nums1[i]:
                imin = i + 1
            elif i > 0 and nums1[i-1] > nums2[j]:
                imax = i - 1
            else:
                if i == 0:
                    max_of_left = nums2[j-1]
                elif j == 0:
                    max_of_left = nums1[i-1]
                else:
                    max_of_left = max(nums1[i-1], nums2[j-1])
                
                if (m + n) % 2 == 1:
                    return max_of_left
                
                if i == m:
                    min_of_right = nums2[j]
                elif j == n:
                    min_of_right = nums1[i]
                else:
                    min_of_right = min(nums1[i], nums2[j])
                
                return (max_of_left + min_of_right) / 2.0





你可能感兴趣的:(算法,算法)