版权声明:转载请记得声明 https://blog.csdn.net/qq_39268193/article/details/80256473
题目
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。
请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。
示例1:
nums1 = [1, 3]
nums2 = [2]
中位数是 2.0
示例2:
nums1 = [1, 2]
nums2 = [3, 4]
中位数是 (2 + 3)/2 = 2.5
解析1:
直接简单粗暴,把两个数组合并在排序,复杂度为O(nlog(n)),但是很明显 复杂大于O(long(m+n))的,不是此题正解
我的代码
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
nums = nums1 + nums2
nums = sorted(nums)
length = len(nums)
if length & 1:
return nums[length//2]
else:
return (nums[length//2 - 1] + nums[length//2]) / 2
解析二:
我们再看,两个有序的数组,这不就是归并吗,通过!但复杂度O(n+m) 但还是要大于O(log(n+m)) , 也不是正解
我的代码
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
nums = self.merge(nums1, nums2)
length = len(nums)
if length & 1:
return nums[length//2]
else:
return (nums[length//2 - 1] + nums[length//2]) / 2
# 归并,将两个有序数组合并为一个有序数组
def merge(self, a, b):
nums = []
while a and b:
if a[0] < b[0]:
nums.append(a.pop(0))
else:
nums.append(b.pop(0))
return nums + a + b
解析三:
虽然上面两种方法都可以通过,但很显然复杂度要大于题目要求的,如果要达到题目要求,我们得用二分思想
思路为下:
1.我们将问题转换为一个寻找第k大数的问题,这样中位数实际上就是第(len_1 + len_2) / 2 + 1大的数。即“寻找第k个元素”
2.令pa = k / 2, pb= k - pa, 如果第一序列的第pa个元素 小于 第二序列第pb个元素 我们不确定二序列第pb个元素是大了还是小了,但一序列的前pb个元素肯定都小于目标,所以我们将第一个序列前p个元素全部抛弃,形成一个较短的新序列。k = k-pa
3.同理,如果第一个序列第p个元素大于第二个序列第q个元素,我们则抛弃第二个序列的前q个元素。k = k - pb
4.如此递归 当较短序列全被抛弃,则返回较长序列的第 k 个元素 或者出现第pa个元素和第pb个元素相等时,就说明中位数就是这个数, 还有刚好当k = 1 时 就返回min(a[0], b[0])
我的代码:
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
len_1 = len(nums1)
len_2 = len(nums2)
length = len_1 + len_2
harf = length >> 1
if length & 1:
return self.find_kth(nums1, len_1, nums2, len_2, harf + 1)
else:
return (self.find_kth(nums1, len_1, nums2, len_2, harf) +
self.find_kth(nums1, len_1, nums2, len_2, harf + 1)) / 2
def find_kth(self, a, len_a, b, len_b, k):
# 保持数组 a 的长度总是小于数组 b 的长度
if len_a > len_b:
return self.find_kth(b, len_b, a, len_a, k)
if len_a == 0:
return b[k-1]
if k == 1:
return min(a[0], b[0])
pa = min(k >> 1, len_a)
pb = k - pa
if a[pa-1] < b[pb-1]:
return self.find_kth(a[pa:], len_a-pa, b, len_b, k-pa)
elif a[pa-1] > b[pb-1]:
return self.find_kth(a, len_a, b[pb:], len_b-pb, k-pb)
else:
return a[pa-1]