LeetCode 4. 寻找两个有序数组的中位数(难)

Posted tonydandelion2014

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 4. 寻找两个有序数组的中位数(难)相关的知识,希望对你有一定的参考价值。

📖 ​题目

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

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

你可以假设 nums1nums2不会同时为空。

📝 示例

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

则中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]

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

🛰 考察知识点

折半查找、边界判定、无尾递归

💡 核心思想

参考链接

将两个有序数组重组,求中位数。👎

将问题 转化为在两个数组中找第 K 个小的数 。 👍

求中位数,其实就是求第 k 小数的一种特殊情况。

首先在两个数组中分别找出第k/2大的数,再比较这两个第 k/2大的数,这里假设两个数组为 A ,B。

那么比较结果会有下面几种情况:

  • A[k/2] = B[k/2],那么第 k 大的数就是 A[k/2]
  • A[k/2] > B[k/2],那么第 k 大的数肯定在 A[0:k/2+1] 和 B[k/2:] 中,这样就将原来的所有数的总和减少到一半了,再在这个范围里面找第 k/2 大的数即可,这样也达到了二分查找的区别了。
  • A[k/2] < B[k/2],那么第 k 大的数肯定在 B[0:k/2+1]和 A[k/2:] 中,同理在这个范围找第 k/2 大的数就可以了。

反复递归执行上述过程即可

💾 Python版本

  • 不满足算法复杂度的一个版本
# coding: utf-8
class Solution:
    # 冒泡排序1    
    def bubbleSort(self, alist: list)  -> list:
        list_len = len(alist)
        exchange = False
        for i in range(list_len-1, 0, -1):  # 从后往前遍历
            for j in range(0, i):  # 从前往后遍历
                if alist[j] > alist[j+1]:  # 如果前面的比后面的大
                    alist[j], alist[j+1] = alist[j+1], alist[j]
                    exchange = True
            # 一次内层循环确定之后就判断一下是不是交换了,没有交换就说明顺序全部正确
            if not exchange:
                break
        return alist

    def findMedianSortedArrays(self, nums1: list, nums2: list) -> float:
        # step1 合并两个list
        sum_list = nums1 + nums2
        # step2 对合并list排序
        sum_list = self.bubbleSort(sum_list)
        # step3 输出中间值
        list_length = len(sum_list)
        k = int(list_length/2)
        if list_length%2==0:  # 偶数个数字
            mid_num1 = sum_list[k-1]
            mid_num2 = sum_list[k]
            mid_num = float(mid_num1+mid_num2)/2 
        else:  # 奇数个数字
            mid_num = float(sum_list[k])
        
        return mid_num

print("leet code accept!!!")
nums1 = [[1, 3, 4, 7]]
nums2 = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
Answer = [4.5]

if __name__ == "__main__":
    solution = Solution()
    for i in range(len(nums1)):
        result = solution.findMedianSortedArrays(nums1[i], nums2[i])
        print(result==Answer[i])

满足O(log(m+n))复杂度的一个算法

class Solution:
    def findMedianSortedArrays(self, nums1: list, nums2: list) -> float:
        n = len(nums1)
        m = len(nums2)
        left = int((n+m+1)/2)
        right = int((n+m+2)/2)
        # a1 = self.getKth(nums1, 0, n-1, nums2, 0, m-1, left)
        # b1 = self.getKth(nums1, 0, n-1, nums2, 0, m-1, right)
        # return (a1+b1)*0.5
        return (self.getKth(nums1, 0, n-1, nums2, 0, m-1, left) + self.getKth(nums1, 0, n-1, nums2, 0, m-1, right)) * 0.5

    def getKth(self, nums1: list, start1: int, end1: int, nums2: list, start2: int, end2: int, k: int):
        len1 = end1 - start1 + 1
        len2 = end2 - start2 + 1
        if len1 > len2:
            return self.getKth(nums2, start2, end2, nums1, start1, end1, k)
        if len1 == 0:
            return nums2[start2+k-1]
        if k == 1:
            return min(nums1[start1], nums2[start2])

        i = int(start1 + min(len1, k/2) - 1)
        j = int(start2 + min(len2, k/2) - 1)

        if nums1[i] > nums2[j]:
            return self.getKth(nums1, start1, end1, nums2, j+1, end2, k-(j-start2+1))
        else:
            return self.getKth(nums1, i+1, end1, nums2, start2, end2, k-(i-start1+1))


print("leet code accept!!!")
nums1 = [[1, 3, 4, 7], [1, 2, 3]]
nums2 = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [4, 5, 6, 7, 8, 9]]
Answer = [4.5, 5]

if __name__ == "__main__":
    solution = Solution()
    for i in range(len(nums1)):
        print("-"*50)
        result = solution.findMedianSortedArrays(nums1[i], nums2[i])
        # print(result)
        # print(Answer[i])
        print(result==Answer[i])
  • 上述算法的时空复杂度分析

时间复杂度:每进行一次循环,减少 k/2 个元素,所以时间复杂度是 O(log(k),而 k = (m+n) / 2,所以最终的复杂也就是 O(log(m+n)。

空间复杂度:虽然用到了递归,但是可以看到这个递归属于尾递归(见通用算法知识),所以编译器不需要不停地堆栈,所以空间复杂度为 O(1)。

💻 有效语法糖

1、python3的range函数实现从后往前循环

a = list(range(9, 0, -1))  # range(start: int, stop: int, step: int)
print(a)
[output] [9, 8, 7, 6, 5, 4, 3, 2, 1]

以上是关于LeetCode 4. 寻找两个有序数组的中位数(难)的主要内容,如果未能解决你的问题,请参考以下文章

[LeetCode] 4. 寻找两个有序数组的中位数

LeetCode 4. 寻找两个有序数组的中位数(难)

LeetCode 4. 寻找两个有序数组的中位数(难)

LeetCode 第4题 寻找有序数组的中位数

Leetcode寻找两个有序数组的中位数

[leetcode]4寻找两个有序数组的中位数