Leetcode 4. Median of Two Sorted Arrays

1.将nums1,nums2所有的数分到两个组(group1, group2)内,保证第一个组的所有元素<=第二个组,且第一个组的元素个数为num1 + nums2元素众数整除2(total//2),如果找到这样的分组,则分奇偶讨论。1)总元素个数为偶数时,中位数为(max(group1), min(group2))/2。2)总元素个数为奇数时,中位数为min(group2)。

2.如果确定了nums1被分到第一组的元素个数(count_1),那么通过total//2-count_1也能确定nums2被分到第一组的元素个数。

假设在nums1数组index=i后切移到,在nums2数组index=j后切一刀,如:                       

 { nums1[0], nums1[1], ... nums1[i] }∈group1,{nums1[i+1], nums1[i+2], ...nums1[-1]}∈group2                  

{ nums2[0], nums2[1], ... nums2[j] }∈group1,{nums2[j+1], nums2[j+2], ...nums2[-1]}∈group2                  

其中group1中元素数量为total//2,即满足(i+1) + (j+1) = total // 2                                                                     

Case1. 如果满足nums1[i] <= nums2[j+1] 且 nums2[j] <= nums1[i+1],则说明满足了group1中的元素全部小于group2中的元素。此时分组完成,可以通过1中的方法直接找到中位数。

Case2. 如果nums1[i] < nums2[j+1],说明nums1分入group1的元素偏少了,nums1切的位置应该在{nums1[i+1], nums1[i+2], ...nums1[-1]}中

Case3.如果nums2[j] < nums1[i+1],说明nums1分入group1的元素偏多了,nums1切的位置应该在{ nums1[0], nums1[1], ... nums1[i] }中

3.以上过程可以通过二分搜索的方式查找nums1数组在何处切了一刀
 

class Solution(object):

    def getMedian(self, nums):

        if len(nums) % 2 == 1:

            return nums[len(nums) // 2]

        else:

            return (nums[len(nums) // 2] + nums[len(nums) // 2 - 1]) / 2.0

    def findMedianSortedArrays(self, nums1, nums2):

        """

        :type nums1: List[int]

        :type nums2: List[int]

        :rtype: float

        """

        if not nums1:

            return self.getMedian(nums2)

        if not nums2:

            return self.getMedian(nums1)

        # 保证左边的元素 <= 右边的元素

        total = len(nums1) + len(nums2)

        left_half = total // 2

        head = 0

        tail = len(nums1)

        while True:

            # 左边包含了nums1[0]...nums1[cut1]

            # 以及 nums2[0]...nums2[cut2]   

            if tail == 0:

                cut1 = -1

                break

            cut1 = (head + tail) // 2

            cut2 = left_half - (cut1 + 1) - 1

            # case1: 左半部分包含的nums1元素超过了总体半数,cut1应当向左移

            if cut2 < -1:

                tail = cut1

            # case2: 左半部分包含的nums1元素过少,导致nums2全部放入左半部分也不够,cut1应当向右移

            elif cut2 >= len(nums2):

                head = cut1 + 1

            else:

                # case 3:nums1[cut1] > nums2[cut2 + 1],cut1应当向左移

                if cut1 >= 0 and cut2 + 1 < len(nums2) and nums1[cut1] > nums2[cut2 + 1]:

                    tail = cut1

                # case 4:nums2[cut2] > nums1[cut1 + 1],cut1应当向右移

                elif cut2 >= 0 and cut1 + 1 < len(nums1) and nums2[cut2] > nums1[cut1 + 1]:

                    head = cut1 + 1

                else:

                    # case 5

                    # 找到合理的划分

                    break

        cut2 = left_half - (cut1 + 1) - 1

        max_num = max(nums1[-1], nums2[-1])

        min_num = min(nums1[0], nums2[0])

        a1 = min_num if cut1 < 0 else nums1[cut1]

        b1 = min_num if cut2 < 0 else nums2[cut2]

        a2 = max_num if cut1 + 1 >= len(nums1) else nums1[cut1 + 1]

        b2 = max_num if cut2 + 1 >= len(nums2) else nums2[cut2 + 1]

        if total % 2 == 1:

            return min(a2, b2)

        else:

            return (max(a1, b1) + min(a2, b2)) / 2.0

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值