1. 概述

在本教程中,我们将讨论如何在一个经典问题中查找两个有序数组并集中的第 K 小元素。我们将从一个朴素解法入手,然后逐步优化,最终使用二分搜索方法实现更高效的算法。

文章末尾我们会对比两种方法的优劣,并说明何时更适合使用哪一种。


2. 问题定义

我们有两个数组:

  • 数组 A(长度为 n)
  • 数组 B(长度为 m)

它们都是升序排列的。我们还需要一个整数 k,要求找出 A 与 B 的合并有序数组 C中的第 k 小元素。

举个例子:

Example

在这个例子中:

  • A = [1, 3, 5, 7]
  • B = [2, 4, 6, 8, 9]
  • 合并后 C = [1, 2, 3, 4, 5, 6, 7, 8, 9]

当 k = 6 时,第 6 小的元素是 7。


3. 朴素解法

✅ 实现思路

我们可以模拟归并排序中“合并两个有序数组”的过程,逐步选出第 k 个元素。我们维护两个指针 i 和 j,分别指向 A 和 B 的当前元素。

每一步我们选择 A[i] 和 B[j] 中较小的那个作为当前最小值,并将对应指针前移。直到我们找到第 k 个最小值为止。

✅ 示例代码

algorithm NaiveApproach(A, B, n, m, k):
    i <- 0
    j <- 0
    answer <- 0

    while i + j < k:
        if i = n:
            answer <- B[j]
            j <- j + 1
        else if j = m:
            answer <- A[i]
            i <- i + 1
        else if B[j] < A[i]:
            answer <- B[j]
            j <- j + 1
        else:
            answer <- A[i]
            i <- i + 1

    return answer

⚠️ 时间复杂度

  • 时间复杂度:O(k)
  • 最坏情况下 k = n + m,复杂度为 O(n + m)

❌ 缺点

虽然实现简单,但效率较低,尤其在 k 很大的时候。


4. 二分搜索解法

4.1 基本思想

我们希望利用二分搜索来加速查找过程。核心思路是:

  • 在数组 A 中尝试选取 i 个元素,那么在数组 B 中就选取 j = k - i 个元素
  • 检查当前 i 是否满足:A[i - 1] <= B[j] 且 B[j - 1] <= A[i]

如果满足,则说明我们已经找到一个合法的分割点,可以确定第 k 小元素的值。

4.2 实现代码

algorithm BinarySearchApproach(A, B, n, m, k):
    bestI <- 0
    L <- max(0, k - m)
    R <- n

    while L <= R:
        mid <- (L + R) / 2
        i <- mid
        j <- k - i

        if j = 0 or A[i - 1] > B[j - 1]:
            R <- mid - 1
            bestI <- mid
        else:
            L <- mid + 1

    i <- bestI
    j <- k - i

    if i != 0:
        return min(B[j], A[i - 1])
    else:
        return B[j - 1]

4.3 示例演示

以 A = [1, 3, 5, 7], B = [2, 4, 6, 8, 9], k = 6 为例:

  • 第一步:mid = 2, i = 2, j = 4 → A[1] = 3 vs B[3] = 8 → 不满足
  • 第二步:mid = 3, i = 3, j = 3 → A[2] = 5 vs B[2] = 6 → 不满足
  • 第三步:mid = 4, i = 4, j = 2 → A[3] = 7 vs B[1] = 4 → 满足

最终返回 min(B[2], A[3]) = min(6, 7) = 6,结果正确。

✅ 时间复杂度

  • 时间复杂度:**O(log n)**,其中 n 是数组 A 的长度

✅ 优势

  • 比较次数大幅减少
  • 特别适合 k 很大时使用

5. 两种方法对比

特性 朴素解法 二分搜索解法
实现难度 ✅ 简单 ⚠️ 稍复杂
时间复杂度 O(k) O(log n)
适用场景 k 较小 k 较大
是否需要合并数组 ❌ 不需要 ❌ 不需要

✅ 如果 k < log n,建议使用朴素解法,因为常数更小,性能更优
✅ 如果 k 接近 n + m,建议使用二分搜索解法,效率更高


6. 总结

我们介绍了在两个有序数组的并集中查找第 k 小元素的问题:

  • 首先使用了朴素解法,模拟归并过程,时间复杂度为 O(k)
  • 然后使用二分搜索方法,将时间复杂度优化到 O(log n)
  • 最后我们对比了两种方法的优劣,指出在不同场景下的选择策略

该问题在算法面试中较为常见,尤其是二分搜索的实现细节容易踩坑,建议多加练习。


原始标题:Finding the Kth Smallest Element in the Union of Two Sorted Arrays