返回

寻求正序数组的折中点:O(log(m+n)) 中位数算法

闲谈

准备着手破解一道颇具挑战性的编程难题吧!想象你拥有两个正序排列的数组,也就是它们内里的数字已经按从小到大的顺序排列妥当。你的任务是找出这两个数组的“中位数”,也就是当把它们合并成一个数组时,正好处于中间位置的那个数字。

现在,事情变得棘手起来:我们要求你使用一种高效的算法,其时间复杂度为 O(log(m+n))。这可不是件容易的事,这意味着算法的运行时间不会随着数组长度的增加而呈指数级增长。

[算法的关键]

为了解决这个难题,我们采用“二分查找”的策略,巧妙地将问题化繁为简。我们先假设这两个数组已经合并成一个更大的数组,然后在这个假设的数组中执行二分查找,找出中位数。

  1. 找出合并数组的长度和中位数索引:

    首先,计算合并数组的长度 m+n。然后,根据这个长度,确定中位数索引 mid,即 (m+n) // 2。

  2. 二分查找中位数:

    现在,我们将对合并数组执行二分查找,不断缩小查找范围,直到找到中位数。

    • 从头尾两个指针 low 和 high 开始,将它们分别初始化为 0 和 m+n-1。

    • 找到中点索引 middle = (low + high) // 2,并计算其在合并数组中的位置:

      • 如果 middle 落在 nums1 中,则位置为 left_part = middle。
      • 如果 middle 落在 nums2 中,则位置为 right_part = middle - m。
    • 检查 left_part 和 right_part 是否等于 mid:

      • 如果相等,则 middle 就是中位数。
      • 如果 left_part 小于 mid,则说明中位数在右侧,因此将 low 更新为 middle + 1。
      • 如果 right_part 小于 mid,则说明中位数在左侧,因此将 high 更新为 middle - 1。
    • 重复步骤 2,直到 low 和 high 相遇。

[代码示例]

为了加深理解,这里提供一个示例代码片段,用 Python 实现上述算法:

def find_median(nums1, nums2):
  m, n = len(nums1), len(nums2)
  low, high = 0, m + n - 1

  while low <= high:
    middle = (low + high) // 2
    left_part = middle if middle < m else middle - m
    right_part = middle - m if middle < m else middle

    if left_part == right_part:
      return nums1[left_part] if left_part < m else nums2[right_part]
    elif left_part < right_part:
      low = middle + 1
    else:
      high = middle - 1

  raise ValueError("Invalid input arrays")

[扩展]

除了解决给定问题外,这种二分查找算法还有广泛的应用场景,如:

  • 查找排序数组中的目标元素
  • 查找有序列表中的特定元素
  • 寻找序列中第一个大于或等于给定值的元素

只要你的问题涉及到在一个有序序列中高效地查找元素,二分查找都是一种强大的工具。掌握这种算法,解锁编程难题的新高度!