LeetCode 4 Median of Two Sorted Arrays 解题报告

原文链接: http://hankerzheng.com/blog/LeetCode-Median-of-Two-Sorted-Arrays

Problem Description

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

Examples:

nums1 = [1, 3]
nums2 = [2]
The median is 2.0

nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5

中文大意:
给定两个排好序的数组, 求数组合并后的中位数, 要求在O(log (m+n))时间复杂度内完成

My Solution

因为时间复杂度是log级别的, 所以我们很容易就想到采用binary search来做, 但是怎么将求中位数转化为binary search呢? 本题目的基本概念就是 求中位数 => 求第k大的数.

注意: 我们用rank表示一个数在数列中的大小的排序序号. 对于一个已经排序的数组nums, 我们可以说nums[rank-1]是数组nums中第rank小的数. 也就是说, rank是1-based index(以1为起始序号的标号方式).

由此我们可以得到一个定理, 假设我们在有序数列nums1中找到了rank1的数, 在有序数列nums2中找到了rank2的数, 并且有nums1[k1 - 1] < nums2[k2 - 1], 那么nums[k2 - 1]rank至少为rank1 + rank2, nums1[k1 - 1]rank至多为rank1 + rank2 - 1.

这个定理也可以推广到n个有序数列中:

假设存在n个有序数列nums1, nums2, …, numsn, 并且我们已知一组元素:
{nums1[rank1-1], nums2[rank2-1], ..., numsn[rankn-1]}.
其中, 所有已知元素中的最大值为numsMax[rankMax-1], 所有已知元素最小值为numsMin[rankMin-1], 那么我们有:
- numsMax[rankMax-1]在所有数中的rank至少为rank1 + rank2 + rank3 + ... + rankn
- numsMin[rankMin-1]在所有数中的rank至多为rank1 + rank2 + rank3 + ... + rankn - n + 1.

利用这个定理, 我们就可以求得两个有序数列中第k大的数:
- 先将k平分成两部分, k = k1 + k2
- 判断nums1[k1]nums2[k2]的大小, 较小的那个数的rank至多为k-1
- 缩减搜索空间, 继续搜索

class Solution(object):
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        length = len(nums1) + len(nums2)
        leftRank = (length + 1) / 2
        rightRank = (length + 2) / 2
        return self.getRank(nums1, 0, nums2, 0, leftRank) / 2.0 + self.getRank(nums1, 0, nums2, 0, rightRank) / 2.0 

    def getRank(self, nums1, start1, nums2, start2, rank):
        if len(nums1) - start1 > len(nums2) - start2:
            return self.getRank(nums2, start2, nums1, start1, rank)
        elif len(nums1) - start1 <= 0:
            return nums2[start2 + rank - 1]
        elif rank == 1:
            return min(nums1[start1], nums2[start2])

        rank1 = min(rank / 2, len(nums1) - start1)
        rank2 = rank - rank1
        if nums1[start1 + rank1 - 1] > nums2[start2 + rank2 - 1]:
            return self.getRank(nums1, start1, nums2, start2 + rank2, rank - rank2)
        elif nums1[start1 + rank1 - 1] < nums2[start2 + rank2 - 1]:
            return self.getRank(nums1, start1 + rank1, nums2, start2, rank - rank1)
        else:
            return nums1[start1 + rank1 - 1]
public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int length = nums1.length + nums2.length;
        int leftRank = (length + 1) / 2; // Rank is 1-base index
        int rightRank = (length + 2) / 2; // Rank is 1-base index
        return getRank(nums1, 0, nums2, 0, leftRank) / 2.0
            + getRank(nums1, 0, nums2, 0, rightRank) / 2.0;
    }

    public int getRank(int[] nums1, int start1, int[] nums2, int start2, int rank){
        if (nums1.length - start1 > nums2.length - start2){
            return getRank(nums2, start2, nums1, start1, rank);
        }else if (start1 >= nums1.length){
            return nums2[start2 + rank - 1];
        }else if (rank == 1){
            return Math.min(nums1[start1], nums2[start2]);
        }

        int rank1 = Math.min(rank / 2, nums1.length - start1);
        int rank2 = rank - rank1;

        if(nums1[start1 + rank1 - 1] > nums2[start2 + rank2 - 1]){
            return getRank(nums1, start1, nums2, start2 + rank2, rank - rank2);
        }else if (nums1[start1 + rank1 - 1] == nums2[start2 + rank2 - 1]){
            return nums1[start1 + rank1 - 1];
        }else{
            return getRank(nums1, start1 + rank1, nums2, start2, rank - rank1);
        }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值