题目:
给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。
请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
示例:
nums1 = [1, 3]nums2 = [2]则中位数是 2.0
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
解法
题目意思简单易懂,就是从两个数组中找到中位数。第一眼看到这个题目想到的方法就是找到中位数是第k个,然后通过分别遍历每个数组找到第k个数,但是题目中有要求算法复杂度为O(log(m + n))。我们只能采取别的方法,看到log的复杂度就想到了二分查找,但是如果在两个数组中实现二分查找呢?
首先,二分查找要分两类讨论,如果是奇数个数组,就选出中间那个,如果是偶数个数字,就选出中间两个数求平均,这样我们的问题就转化成了找到两个数组中第K大的数。
寻找第K大的数也是通过二分查找来实现。我们先记录每个数组的起始位置,这可以方便我们在后面对K求二分时利用偏置,舍弃前面一半的数。将两个数组的起始位置都加上K/2,并确保数组不越界。比较这个位置两个数组中元素的大小,如果第一个数组小于第二个,表示第一个数组中该位置前面的数一定不会是第K个数,可以更新起始位置,并且更新K减去舍弃的数的个数,同理可得第二个数组。
通过不断更新K和起始位置,我们设定结束条件。如果一个数组走完了,那K数就在另一个数组中,直接取第K个,如果K等于1,比较两个数组中第一个数,选出结果。
代码
class Solution: def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float: def getKnum(k): index1,index2 = 0,0 while True: if index1 == m: return nums2[index2+k-1] if index2 == n: return nums1[index1+k-1] if k == 1: return min(nums1[index1],nums2[index2]) newindex1 = min(m-1,index1+k//2-1) newindex2 = min(n-1,index2+k//2-1) p1,p2 = nums1[newindex1],nums2[newindex2] if p1 > p2: k -= newindex2 - index2 + 1 index2 = newindex2 + 1 else: k -= newindex1 - index1 + 1 index1 = newindex1 + 1 m,n = len(nums1),len(nums2) totalnum = m + n if totalnum % 2 == 1: return getKnum((totalnum+1)//2) else: return (getKnum(totalnum//2)+getKnum(totalnum//2+1))/2
总结
简单的二分查找,通过在两个数组中做标记来实现二分的舍弃,受到很大启发。
如果文中存在一些错误,请多多指教。以后也会和大家分享leetcode每日一题的学习,希望大家多多支持。