欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【leetcode】4. Median of Two Sorted Arrays

程序员文章站 2022-07-15 10:47:01
...

Problem Description

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)).
【leetcode】4. Median of Two Sorted Arrays

Solutions

核心思想是要将中位数的定义转化为“Dividing a set into two equal length subsets, that one subset is always greater than the other.”

【leetcode】4. Median of Two Sorted Arrays
代码思路:
1. 第一种情况:两个list中有一个list为空;直接返回另一个list的中位数。
这里有两种方式可解决元素个数的奇/偶需分开讨论的问题:1) 利用向下取整的trick,见代码;2)利用list[m]和list[~m];虽然本质是一样的
2. 在算法中,根据‘two equal length subsets’的约束条件,我们只需loop查询两个list中的一个list即可,因为知道list1的cut的位置,根据等长约束,list2中cut的位置即可计算出。为了提高效率,使时间复杂度为 O(log(min(m,n)))(m, n分别为list1和list2的元素个数),不妨假设m<=n,不满足时调换两个list的位置即可
3. 两个list均非空的情况;寻找使‘left is always greater than right’约束条件成立的list1中cut的位置。这里分三种情况:1) l1 > r2, cut1 需左移;2) l2 > r1, cut1 需右移 3) l1 < r2 and l2 < r1,stop。
4. 有两种边缘特殊情况需考虑:1) max(nums1) < min(nums2) 2) min(nums1) > max(nums2);这里有一个非常巧妙的处理——在list两端分别添加MIN_VALUE和MAX_VALUE,便于将两种边缘特殊情况与普通情况一起处理
5. 两个list均非空的情况返回结果时,需分别考虑元素个数奇偶情况:偶数——返回 (max(left)+min(right))/2;奇数——因为是向下取整,所以右边会多一个元素,返回min(right)即可。

详细代码如下: Github link

# Runtime: 92 ms
class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        MAX_VALUE = float('Inf')
        MIN_VALUE = -float('Inf')

        # 获取list元素个数
        m = len(nums1)
        n = len(nums2)
        if m == 0:  # nums1为空
            # 这里有个小trick
            # n为奇数时,nums2[int((n-1)/2)]和nums2[int(n/2)]是同一个数,即中位数
            # n为偶数时,nums2[int((n-1)/2)]和nums2[int(n/2)]分别为最中间的两个数
            # 这是因为int(n/2)是向下取整,int(1.5) == 1
            # 向下取整的功能也可以通过 '//' 运算符实现
            return float((nums2[int((n - 1) / 2)] + nums2[int(n / 2)]) / 2)
        if n == 0:  # 同理,nums2为空
            return float((nums1[(m - 1) // 2] + nums1[m // 2]) / 2)

        if m > n:  # 为了提高效率,保证进行loop遍历的是较短的list
            return Solution.findMedianSortedArrays(self, nums2, nums1)

        # 两个list均非空的情况
        # 割的范围初始化
        size = m + n
        CutL = 0
        CutR = m
        cut1 = m // 2  # 短list的割的位置

        while cut1 <= m:  # 寻找满足 l1<r2 and l2<r1的割的位置
            cut1 = (CutR - CutL) // 2 + CutL  # 短list的割的位置
            cut2 = size // 2 - cut1  # 长list的割的位置

            # 在list两端分别添加MIN_VALUE和MAX_VALUE,便于将两种边缘特殊情况与普通情况一起处理
            # 两种边缘特殊情况即:1. max(nums1)<min(nums2)  2. min(nums1)>max(nums2)
            # 获取割两边的值
            l1 = MIN_VALUE if cut1 == 0 else nums1[cut1 - 1]  # 相当于Java中的三目运算符'?:',只有当min(nums1)>max(nums2)时,l1取值MIN_VALUE
            l2 = MIN_VALUE if cut2 == 0 else nums2[cut2 - 1]  # 同上,其实取不到特殊情况?
            r1 = MAX_VALUE if cut1 == m else nums1[cut1]  # 只有当max(nums1)<min(nums2时,l1取值MIX_VALUE
            r2 = MAX_VALUE if cut2 == n else nums2[cut2]

            if l1 > r2:  # l1>r2, cut1需左移
                CutR = cut1 - 1
            elif l2 > r1:  # l2>r1, cut1需右移
                CutL = cut1 + 1
            else:  # 满足 l1<r2 and l2<r1
                if size % 2 == 0:  # 两个list的元素总个数为偶数
                    l = l1 if l1 > l2 else l2
                    r = r1 if r1 < r2 else r2
                    return float((l + r) / 2)
                else:  # 两个list的元素总个数为奇数
                    r = r1 if r1 < r2 else r2
                    return float(r)


这是符合时间复杂度要求O(log (m+n))的一种解法,实际时间复杂度为O(log(min(m,n)))

另外有一种时间复杂度为O(nlogn)的解法(考虑sort时间复杂度,虽然这两种解法都可以被accepted),代码简短,各取所需

# sample 88 ms submission
# 我提交这种方案仍然是 Runtime: 92 ms
class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        num = nums1 + nums2
        num = sorted(num)
        l = len(num)
        if l % 2 == 0:
            return (num[l//2-1]+num[l//2])/2*1.0
        else:
            return num[l//2]*1.0


# sample 92 ms submission
class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        nums1 += nums2
        nums1.sort()
        m = int(len(nums1) / 2)
        return (nums1[m] + nums1[~m]) / 2