LeetCode.4 Median of Two Sorted Arrays

今天,小天就不和同学们废话了,直接上题:

题目简介:

给定两个有序的列表,返回两者的中位数。举例说明:输入列表1 [1,3] 列表2 [2],返回2。值得注意的是,题目要求算法时间复杂度需要限定为O(log (m+n))。

解法一:

已知输入的两个列表是有序的,所以可以分别遍历列表得到合并的且有序的列表。实现上也比较简单,但需要注意空列表和两列表长度不一致的情况:

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        i1 = i2 = 0
        l1, l2 = len(nums1), len(nums2)
        c = []
        while i1 < l1 and i2 < l2:
            if nums1[i1] < nums2[i2]:
                c.append(nums1[i1])
                i1 += 1
            else:
                c.append(nums2[i2])
                i2 += 1
        if i1 < l1:
            for i in range(i1, l1):
                c.append(nums1[i])
        if i2 < l2:
            for i in range(i2, l2):
                c.append(nums2[i])
        l3 = len(c)
        half = int(l3 / 2)
        if l3 % 2 == 0: return 0.5 * (c[half - 1] + c[half])
        else: return c[half]  

解法一创建了一个新的列表,并在遍历的时候不断地做列表元素添加操作,这影响了整体的性能。基线耗时为160ms。

解法一:

解法二有点取巧,在python环境下,列表自带的sort操作由于做过优化,故而效率比较高。这里先将两个列表合并,并使用python自带的sort函数进行排序。

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        # nums = nums1 + nums2
        for n in nums2:
            nums1.append(n)
        nums1.sort()
        l = len(nums1)
        half = int(l / 2)
        if l % 2 == 0: return 0.5 * (nums1[half - 1] + nums1[half])
        else: return nums1[half]   

解法二的性能提升非常明显,在基线上测得耗时为100ms。先别急着高兴,对sort函数有所了解的同学可能就会疑问,sort的时间复杂度不是O(nlog (n))吗?小天特意查阅了相关资料,确实如此。在之前几期中,小天就提到python的效率浮动比较大,有些封装好的函数可能耗时非常少。这样一来,我们就不知道是python语言特性还是算法本身带来的增幅,在采用c、c++等语言实现算法时,会大大避免这一情况。

解法三:

解法三比较有意思,利用了中位数两边的元素个数是相同的这一数学特性。解法在官网上有详细的解答,这里就不作细讲,只展示代码实现:

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
       
        m, n = len(nums1), len(nums2)
        if m > n:
            return self.findMedianSortedArrays(nums2, nums1)

        left, right, half_len = 0, m, (m + n) // 2
        while left <= right:
            i = (left + right) // 2
            j  = half_len - i
            if i < m and nums2[j-1] > nums1[i]:
                left = i + 1
            elif i > 0 and nums1[i-1] > nums2[j]:            
                right = 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 i == m: min_of_right = nums2[j]
                elif j == n: min_of_right = nums1[i]
                else: min_of_right = min(nums1[i], nums2[j])
                                        
                if (m + n) % 2 == 1:
                    return min_of_right

                return (max_of_left + min_of_right) / 2.0

为提升效率,算法中运用了折半搜索。这一实现需要考虑边界条件和元素总数为奇数的情况。个人觉得所有解法三更适合作为本题的最优解而非解法二。虽然python环境下基线测得耗时相差不大。

总结:

找到问题的一种解法并不困难,困难的是找到最优解。

猜你喜欢

转载自blog.csdn.net/qq_30818049/article/details/82933265