题目描述:
给定两个数组,这两个数组是排序好的,让你求这两个数组合到一起之后第K大的数。
当然你可以使用遍历,第一个数组长度为n第二个数组长度为m,那么你的方法时间复杂度为o(m +n),但是有更快的方法,时间复杂度接近于O(log(m +n)),接下来介绍这种方法。
基本思路如下,
首先取得数组a的中位数a[aMid],然后在b中二分查找a[aMid],得到b[bMid],b[bSt]到b[bMid]的数小于等于a[aMid],b[bMid+1]到b[bEd]大于等于a[aMid],这样数组a和数组b就被划分为了两个部分,第一个部分的数小于等于a[aMid],第二部分的数大于等于a[aMid],然后统计这两个区域数的个数,剩下的步骤和传统的求一个数组中的第k大的数一样。
#include<iostream>
#include <algorithm>
using namespace std;
int a[] = { 1, 3, 5, 7 };
int b[] = { 2, 4, 6, 8 };
int theDivideFind(int num[],int left, int right, int k)
{
if (left > right)
{
return right;
}
int mid;
while (right >= left)
{
mid = (left + right) / 2;
if (k == num[mid]) return mid;
else if (k < num[mid])
{
right = mid - 1;
}
else
{
left = mid + 1;
}
}
return right;
}
int main()
{
int theResult = -1;
int aSt, aEd;
int bSt, bEd;
aSt = bSt = 0;
aEd = bEd = 3;
int aMid = 0;
int bMid = 0;
int theLeftCount = 0;
int k = 9;
if (k <= 0 || k >= 9)
{
cout << -1 << endl;
return 0;
}
while (1)
{
if (aSt == aEd && bSt == bEd)
{
if (k == 1) theResult = min(a[aSt], b[bSt]);
else
{
theResult = max(a[aSt], b[bSt]);
}
break;
}
theLeftCount = 0;
if (aSt <= aEd)
{
aMid = (aSt + aEd) / 2;
theLeftCount += (aMid - aSt + 1);
if (bSt <= bEd)
{
bMid = theDivideFind(b, bSt, bEd, a[aMid]);
if (bMid >= bSt)
{
theLeftCount += (bMid - bSt + 1);
}
}
}
else
{
aMid = -1;
bMid = (bSt + bEd) / 2;
theLeftCount += (bMid - bSt + 1);
}
if (theLeftCount == k)
{
if(aSt <= aEd)
theResult = a[aMid];
else
{
theResult = b[bMid];
}
break;
}
else if(theLeftCount > k)
{
if (aSt <= aEd)
{
aEd = aMid;
}
if (bSt <= bEd)
{
bEd = bMid;
}
}
else
{
if (aSt <= aEd)
{
aSt = aMid + 1;
}
if (bSt <= bEd)
{
bSt = bMid + 1;
}
k -= theLeftCount;
}
}
cout << theResult << endl;
return 0;
}