问题:给定一个有序(非降序)数组A和一个有序(非降序)数组B,可含有重复元素,求两个数组合并结果中的第k(k>=0)个数字。
这个题目出现了两个数组,有序的,不管怎样我们就应该首先考虑二分查找是否可行。若使用顺序查找,时间复杂度最低为O(k),就是类似归并排序中的归并过程。使用用二分查找时间复杂度为O(logM+logN)。二分查找的具体实现过程请参考实现代码与注释。
这个题目出现了两个数组,有序的,不管怎样我们就应该首先考虑二分查找是否可行。若使用顺序查找,时间复杂度最低为O(k),就是类似归并排序中的归并过程。使用用二分查找时间复杂度为O(logM+logN)。二分查找的具体实现过程请参考实现代码与注释。
- int findKthIn2SortedArrays(int A[], int m, int B[], int n, int k)
- {
- if(m <= 0) // 数组A中没有元素,直接在B中找第k个元素
- return B[k];
- if(n <= 0) // 数组B中没有元素,直接在A中找第k个元素
- return A[k];
- int i = (m-1)>>1; // 数组A的中间位置
- int j = (n-1)>>1; // 数组B的中间位置
- if(A[i] <= B[j]) // 数组A的中间元素小于等于数组B的中间元素
- {
- /*
- 设x为数组A和数组B中小于B[j]的元素数目,则i+1+j+1小于等于x,
- 因为A[i+1]到A[m-1]中还可能存在小于等于B[j]的元素;
- 如果k小于i+1+j+1,那么要查找的第k个元素肯定小于等于B[j],
- 因为x大于等于i+1+j+1;既然第k个元素小于等于B[j],那么只
- 需要在A[0]~A[m-1]和B[0]~B[j]中查找第k个元素即可,递归调用下去。
- */
- if(k < i+1+j+1)
- {
- if(j > 0)
- return findKthIn2SortedArrays(A, m, B, j+1, k);
- else // j == 0时特殊处理,防止死循环
- {
- if(k == 0)
- return min(A[0], B[0]);
- if(k == m)
- return max(A[m-1], B[0]);
- return A[k] < B[0] ? A[k] : max(A[k-1], B[0]);
- }
- }
- /*
- 设y为数组A和数组B中小于于等于A[i]的元素数目,则i+1+j+1大于等于y;
- 如果k大于等于i+1+j+1,那么要查找到第k个元素肯定大于A[i],因为
- i+1+j+1大于等于y;既然第k个元素大于A[i],那么只需要在A[i+1]~A[m-1]
- 和B[0]~B[n-1]中查找第k-i-1个元素,递归调用下去。
- */
- else
- return findKthIn2SortedArrays(A+i+1, m-i-1, B, n, k-i-1);
- }
- // 如果数组A的中间元素大于数组B的中间元素,那么交换数组A和B,重新调用即可
- else
- return findKthIn2SortedArrays(B, n, A, m, k);
- }