在两个有序数组中寻找第k个元素

来源:互联网 发布:黄金分割线软件 编辑:程序博客网 时间:2024/05/17 02:32

这个问题很经典,有必要好好梳理一下:

函数的参数设定为,数组A,A的长度m,数组B,B的长度n,需要找的k。

  1. 如果m + n < k,那么无论如何也找不到满足要求的数了;
  2. 如果m和n其一为0,那么就应该返回另一个数组的k - 1位置的元素;
  3. 否则,将A(近似地)平均分为两部分,记其分点下标为i = m / 2,B也如此做,其分点下标为j = n / 2。假设A[i] <= B[j],如果不是这样,那么就将A、B互换,i、j,m、n也需要互换。
如此,B[j]将不小于B中它之前的所有元素,并且也不小于A[i],进而推得不小于A中A[i]前的所有元素。这说明,如果我们将A、B数组合并,B[j]前(不包括B[j])将至少有i + j + 1个元素。如果k <= i + j + 1,我们要找的元素一定在B[j]的前面,合并后排在B[j]后的元素将不可能是解,将其直接抛弃,而我们此时能确定的合并后一定排在B[j]后的元素就是B中B[j]后的元素,将其舍弃。

在A中,A[i]之后一共有m - i - 1个元素,B[j]及其之后共有n - j个元素。又由于A[i] <= B[j],合并后,A[i]之后(不包括A[i])将至少有m - i - 1 + n - j = (m + n) - (i + j + 1)个元素。这说明,合并后A[i]之前(包括A[i])至多有i + j + 1个元素。如果k > i + j + 1,那么我们要找的元素不可能在A[i]之前,A[i]及其之前的所有元素可以被舍弃。

综上便可以得到代码:

class FindKthIn2Arrays {private:int findKthIn2Arrays(int A[], int m, int B[], int n, int k) {if (m + n < k)return -1;if (m == 0)return B[k - 1];if (n == 0)return A[k - 1];int *p, *q, i, j, t;i = m / 2;j = n / 2;if (A[i] <= B[j]) {p = A;q = B;}else {p = B;q = A;swap(i, j);swap(m, n);}t = i + j + 1;if (k <= t)return findKthIn2Arrays(p, m, q, j, k);elsereturn findKthIn2Arrays(p + i + 1, m - (i + 1), q, n, k - (i + 1));}public:void tester() {int A[5], B[5];for (int i = 0; i < 5; ++i) {A[i] = 2 * i;B[i] = 2 * i + 1;}cout << findKthIn2Arrays(A, 5, B, 5, 2) << endl;}};


0 0