Leetcode No.4 两个排序数组的中位数/Median of Two Sorted Arrays

问题描述:

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 

请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。

你可以假设 nums1 和 nums2 均不为空

示例:

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

中位数是 (2 + 3)/2 = 2.5

 

思路与分析:

1.直接合并:

思路:

用归并排序的思路合并两个有序数组,直接求中位数

时间复杂度:

只需扫描一遍两个数组,复杂度是O(m+n)

笔者尝试着提交了这份code发现可以通过= =

虽然已经足够快了,但还是达不到题目要求的对数时间复杂度O(log(m+n)),所以要换一种思路

 

2.Binary Search

思路:

由对数时间的复杂度很容易联想到树的查找与二分查找

(1)如果使用二叉树来做

首先要build binary tree,这个过程中每次insert需要O(log(n+m))的时间,把 n + m 个元素放到树上需要O((n+m)log(n+m))的时间,已经超时了= = 

(2)二分查找

本题思路非常巧妙,LeetCode上已有详尽解答,我在这里记录下个人的理解。

我们的目的是求出中位数,从中位数的定义出发,它将一个序列切成等长的两半,而且左半边的任意元素一定小于右半边的任意元素。

求一个有序数组的中位数,直接取中即可;

求两个有序数组A,B的中位数,用同样的思路,找两个分界点 i 和 j, 分别把A, B切开,

我们得到四段有序数组:A_left, A_right, B_left, B_right  

把 A_left 和 B_left 放在一起叫 left_part,把 A_right 和 B_right 放在一起叫 right_part

假如 left_part 和 right_part 长度相等,而且 max(left_part) <= min(right_part),就表明我们成功地将集合{A, B}的元素分成等长

的两半,而且左半边的任意元素一定小于右半边的任意元素,满足了中位数的定义,此时

                                    median = ( max(left_part) + min(right_part) )/2

翻译一下这两个条件:

   (1)left_part 和 right_part 长度相等 ——> i + j = m - i + n - j + 1,即 j = (n+m+1)/2 - i 

     (2)max(left_part) <= min(right_part) ——> A[i - 1] <= B[ j ] and B[j - 1] <= A[ i ]

     #数组A和B的长度分别为m,n

换言之,我们要找到一个 , 使得以下式子成立:A[i - 1] <= B[ j ] and B[j - 1] <= A[ i ],其中 j = (n+m+1)/2 - i

由于m、n已知,是由 i 唯一确定的,只要找到这个 i ,我们就收工了:)

 

目标转换成在有序数组A中查找一个符合要求的元素 A[ i ],现在的任务是查找!

在有序数组中查找元素,毫无疑问就是二分查找了

用 imin ,imax 标记查找的边界,初始时 imin = 0 imax = m

对于二分查找,无非会遇到三种情况:

(1)是完美的:A[i - 1] <= B[ j ] and B[j - 1] <= A[ i ],done√

(2)偏小,意味着 B[j - 1] > A[ i ],调整边界到 i 的右侧查找:imin = i+1

(3)偏大,意味着 A[i - 1] > B[ j ],调整边界到 i 的左侧查找:imax = i - 1

 

查找过程中还会遇到一些边界情况:i = 0, m 以及 j = 0, n,这个看官方解答很容易理解,不再赘述

 

时间复杂度:

O(log(n+m))

 

代码实现(Python):

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        A, B = nums1, nums2
        m, n = len(A), len(B)
        if m > n:
            A, B, m, n = B, A, n, m
        if n == 0:
            raise ValueError
        imin, imax, half_of_len = 0, m, (n+m+1)/2
        while imin <= imax:
            i = (imin+imax)/2
            j = half_of_len - i
            if i < m and A[i] < B[j-1]:
                # i is too small, increase it
                imin = i + 1
            elif i > 0 and B [ j ] < A[i-1]:
                # i is too big, decrease it
                imax = i - 1
            else:
                # i is perfect
                if i == 0:    max_of_left = B[j-1]
                elif j == 0:    max_of_left = A[i-1]
                else:     max_of_left = max(A[i-1], B[j-1])

                if (m+n)%2 == 1:
                    return max_of_left

                if i == m:    min_of_right = B[j]
                elif j == n:    min_of_right = A[i]
                else:    min_of_right = min(A[i], B[j])

                return (max_of_left+min_of_right)/2.0

 

 

Reference

https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值