题目分析
- 题目给出了我们两个递增数组
- 题目要求我们返回两个数组中所有数字的中位数
方法一:双指针归并
- 实现思路
-
由于我们知道两个数组是升序的,我们用双指针的方式对两个表进行遍历
-
比较两个指针所指数字的大小选择是否要移动指针,进行不断迭代
-
直到两个指针所指数字某一个指针率先达到了中位数目标位置,则返回最终的数字
-
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param arr1 int整型一维数组
# @param arr2 int整型一维数组
# @return int整型
#
class Solution:
def getUpMedian(self , arr1: List[int], arr2: List[int]) -> int:
# write code here
k = int((len(arr1)+len(arr2))/2)
i, idx1, idx2 = 0, -1, -1
f1, f2 = 0, 0
while i < k:
if idx1+1 < len(arr1) and idx2+1 < len(arr2): # 两列表都未越界
if arr1[idx1+1] < arr2[idx2+1]: # 比较哪一个小,哪一个下标移动
idx1 += 1
f1, f2 = 1, 0
else:
idx2 += 1
f1, f2 = 0, 1
elif idx1+1 < len(arr1): # 只有列表1未越界
idx1 += 1
f1, f2 = 1, 0
else: # 只有列表2未越界
idx2 += 1
f1, f2 = 0, 1
i += 1
if f1:
return arr1[idx1]
else:
return arr2[idx2]
复杂度分析
- 时间复杂度:,其中是的长度,是的长度,由于遍历只有一趟,因此时间代价和长度之和成线性关系
- 空间复杂度:,只引入常量级别的空间开销
方法二:二分法
- 实现思路
- 假设两个有序数组分别是 和 。要找到第 个元素,我们可以比较 和 ,其中 表示整数除法。由于 和 的前面分别有 和 ,即 个元素,对于 和 中的较小值,最多只会有 个元素比它小,那么它就不能是第 小的数了。
- 因此我们可以归纳出2种情况:
- 如果 ,则比 小的数最多只有 的前 个数和 的前 个数,即比 小的数最多只有 个,因此 不可能是第 个数, 到 也都不可能是第 个数,可以全部排除。
- 如果 ,则可以排除 到 。
- 比较 和 之后,可以排除 个不可能是第 小的数,查找范围缩小了一半。如果 和 越界,则 减小时要根据排除的数字数量减小。同时,我们将在排除后的新数组上继续进行二分查找,并且根据我们排除数的个数,减少 的值,这是因为我们排除的数都不大于第 小的数。
- 如果一个数组已经为空,则直接返回另一个数组的第 小的数字
- 如果 ,直接返回两个数组首位的较小的元素即可
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param arr1 int整型一维数组
# @param arr2 int整型一维数组
# @return int整型
#
class Solution:
def getUpMedian(self , arr1: List[int], arr2: List[int]) -> int:
# write code here
def getKth(k):
idx1, idx2 = 0, 0
while True:
if idx1 == m: # arr1 全部被排除
return arr2[idx2 + k -1]
if idx2 == n: # arr2 全部被排除
return arr1[idx1 + k -1]
if k == 1: # k减少到1的情况
return min(arr1[idx1], arr2[idx2])
nidx1 = min(m - 1, idx1 + k // 2 - 1) # 进行下一次二分
nidx2 = min(n - 1, idx2 + k // 2 - 1) # 进行下一次二分
pivot1, pivot2 = arr1[nidx1], arr2[nidx2]
if pivot1 <= pivot2:
k -= nidx1 - idx1 + 1
idx1 = nidx1 + 1
else:
k -= nidx2 - idx2 + 1
idx2 = nidx2 + 1
m, n = len(arr1), len(arr2)
if (m + n) % 2 == 1:
return getKth((m + n + 1) // 2)
else:
return getKth((m + n) // 2)
复杂度分析
- 时间复杂度:,其中是的长度,是的长度,由于代码对两个数组进行分开的二分操作,因此时间代价是对数级别的
- 空间复杂度:,只引入了常量级别的空间开销。