给定两个已经排序好的数组,找到两者所有元素中第 k 大的元素
2017-03-28 15:33
399 查看
给定两个已经排序好的数组,找到两者所有元素中第 k 大的元素。假设为A,B都按升序排列。
方法一: 直接 merge 两个数组(即将两个已排好序的数组合并为一个排好序的新数组(m+n个元素),然后求第 k 大的元素,时间复杂度为O(m + n);可以用一个计数器,记录当前已经找到第 m 大的元素了。同时我们使用两个指针
pA 和 pB,分别指向 A 和 B 数组的第一个元素,使用类似于 merge sort 的原理,如果数组 A 当前元素小,那么 pA++,同时 m++;如果数组
B 当前元素 小,那么 pB++,同时 m++。最终当 m 等于 k 的时候,就得到了我们的答案,O(k)时间,O(1) 空间。但是,当 k 很接近 m + n 的时候,这个方法时间复杂还是 O(m + n) 。
C++代码:
int findKthMaxNumOfArrays(int A[],int m,int B[],int n,int k)
{
int *pA=A;
int *pB=B;
int i=0;
int j=0;
int cur=0;
while(i<m&&j<n)
{
if(A[i]<B[j])
{
cur++;
if(cur==k) return A[i];
i++;
}
else
{
cur++;
if(cur==k) return B[j];
j++;
}
}
while(i<m)
{
cur++;
if(cur==k) return A[i];
i++;
}
while(j<n)
{
cur++;
if(cur==k) return B[j];
j++;
}
}
方法二: 由于 A 和 B 都是有序的,利用这里面的信息,类似于二分查找。时间复杂度可以缩短到
![](http://qqadapt.qpic.cn/adapt/0/8307aa08-c99c-aa57-00b0-bbdf71bef2ae/800?pt=0&ek=1&kp=1&sce=0-12-12)
假设 A 和 B 的元素个数都大于 k/2,我们将 A 的第 k/2 个元素(即 A[k/2-1])和 B 的第 k/2个元素(即 B[k/2-1])进行比较,
有以下三种情况(为了简化这里先假设 k 为偶数,所得到的结论对于 k 是奇数也是成立的):
• A[k/2-1] == B[k/2-1]
• A[k/2-1] > B[k/2-1]
• A[k/2-1] < B[k/2-1]
如果 A[k/2-1] < B[k/2-1],意味着 A[0] 到 A[k/2-1 ]的肯定在 A ∪ B 的 top k 元素的范围内,换句话说,A[k/2-1 ]不可能大于 A ∪ B 的第 k 大元素。因此,我们可以放心的删除 A 数组的这 k/2 个元素。同理,当 A[k/2-1]
> B[k/2-1] 时,可以删除 B 数组的 k/2 个元素。当 A[k/2-1] == B[k/2-1] 时,说明找到了第 k 大的元素,直接返回 A[k/2-1] 或 B[k/2-1]
因此,我们可以写一个递归函数。那么函数终止条件如下:
• 当 A 或 B 是空时,直接返回 B[k-1] 或 A[k-1];
• 当 k=1 是,返回 min(A[0], B[0]);
• 当 A[k/2-1] == B[k/2-1] 时,返回 A[k/2-1] 或 B[k/2-1]
int findKthMaxNumOfArrays(int A[],int m,int B[],int n,int k)
{
if(m>n)
return findKthMaxNumOfArrays(B,n,A,m,k); //假设m永远<=n;
if(m==0)
return B[k-1];
if(k==1)
return ((A[0]>=B[0]?B[0]:A[0]));
int k2=k>>1;
int pA=((k2>=m)?m:k2);
int pB=k-pA;
if(A[pA-1]<B[pB-1])
return findKthMaxNumOfArrays(A+pA,m-pA,B,n,k-pA);
else if(A[pA-1]>B[pB-1])
return findKthMaxNumOfArrays(A,m,B+pB,n-pB,k-pB);
else
return A[pA-1];
}
方法三、判断a[mid_a] 与 b[mid_b]的关系(同二类似)
如果A[mida] < B[mid_b]
1)k小于等于mida + midb + 1,那么B数组从mid_b开始就没有用了,缩小B的搜索范围
2)k大于mida + midb + 1, 那么A数组从low到mid_a开始就没用了,缩小A的搜索范围
3)终止条件是 A搜索完 返回B中元素或者相反
找到两者所有元素的中位数
int findMedianSortedArrays(int A[], int m, int B[], int n)
{
int total = m + n;
if (total & 0x1)
return findKth(A, m, B, n, total / 2 + 1); //m+n为奇数
else
return (findKth(A, m, B, n, total / 2)
+ findKth(A, m, B, n, total / 2 + 1)) / 2; //m+n为偶数
}
方法一: 直接 merge 两个数组(即将两个已排好序的数组合并为一个排好序的新数组(m+n个元素),然后求第 k 大的元素,时间复杂度为O(m + n);可以用一个计数器,记录当前已经找到第 m 大的元素了。同时我们使用两个指针
pA 和 pB,分别指向 A 和 B 数组的第一个元素,使用类似于 merge sort 的原理,如果数组 A 当前元素小,那么 pA++,同时 m++;如果数组
B 当前元素 小,那么 pB++,同时 m++。最终当 m 等于 k 的时候,就得到了我们的答案,O(k)时间,O(1) 空间。但是,当 k 很接近 m + n 的时候,这个方法时间复杂还是 O(m + n) 。
C++代码:
int findKthMaxNumOfArrays(int A[],int m,int B[],int n,int k)
{
int *pA=A;
int *pB=B;
int i=0;
int j=0;
int cur=0;
while(i<m&&j<n)
{
if(A[i]<B[j])
{
cur++;
if(cur==k) return A[i];
i++;
}
else
{
cur++;
if(cur==k) return B[j];
j++;
}
}
while(i<m)
{
cur++;
if(cur==k) return A[i];
i++;
}
while(j<n)
{
cur++;
if(cur==k) return B[j];
j++;
}
}
方法二: 由于 A 和 B 都是有序的,利用这里面的信息,类似于二分查找。时间复杂度可以缩短到
假设 A 和 B 的元素个数都大于 k/2,我们将 A 的第 k/2 个元素(即 A[k/2-1])和 B 的第 k/2个元素(即 B[k/2-1])进行比较,
有以下三种情况(为了简化这里先假设 k 为偶数,所得到的结论对于 k 是奇数也是成立的):
• A[k/2-1] == B[k/2-1]
• A[k/2-1] > B[k/2-1]
• A[k/2-1] < B[k/2-1]
如果 A[k/2-1] < B[k/2-1],意味着 A[0] 到 A[k/2-1 ]的肯定在 A ∪ B 的 top k 元素的范围内,换句话说,A[k/2-1 ]不可能大于 A ∪ B 的第 k 大元素。因此,我们可以放心的删除 A 数组的这 k/2 个元素。同理,当 A[k/2-1]
> B[k/2-1] 时,可以删除 B 数组的 k/2 个元素。当 A[k/2-1] == B[k/2-1] 时,说明找到了第 k 大的元素,直接返回 A[k/2-1] 或 B[k/2-1]
因此,我们可以写一个递归函数。那么函数终止条件如下:
• 当 A 或 B 是空时,直接返回 B[k-1] 或 A[k-1];
• 当 k=1 是,返回 min(A[0], B[0]);
• 当 A[k/2-1] == B[k/2-1] 时,返回 A[k/2-1] 或 B[k/2-1]
int findKthMaxNumOfArrays(int A[],int m,int B[],int n,int k)
{
if(m>n)
return findKthMaxNumOfArrays(B,n,A,m,k); //假设m永远<=n;
if(m==0)
return B[k-1];
if(k==1)
return ((A[0]>=B[0]?B[0]:A[0]));
int k2=k>>1;
int pA=((k2>=m)?m:k2);
int pB=k-pA;
if(A[pA-1]<B[pB-1])
return findKthMaxNumOfArrays(A+pA,m-pA,B,n,k-pA);
else if(A[pA-1]>B[pB-1])
return findKthMaxNumOfArrays(A,m,B+pB,n-pB,k-pB);
else
return A[pA-1];
}
方法三、判断a[mid_a] 与 b[mid_b]的关系(同二类似)
如果A[mida] < B[mid_b]
1)k小于等于mida + midb + 1,那么B数组从mid_b开始就没有用了,缩小B的搜索范围
2)k大于mida + midb + 1, 那么A数组从low到mid_a开始就没用了,缩小A的搜索范围
3)终止条件是 A搜索完 返回B中元素或者相反
找到两者所有元素的中位数
int findMedianSortedArrays(int A[], int m, int B[], int n)
{
int total = m + n;
if (total & 0x1)
return findKth(A, m, B, n, total / 2 + 1); //m+n为奇数
else
return (findKth(A, m, B, n, total / 2)
+ findKth(A, m, B, n, total / 2 + 1)) / 2; //m+n为偶数
}
相关文章推荐
- (笔试中的题目)一个已经排序好的数组找到两个数字相加等于一个给定的数
- Java 找到数组中两个元素相加等于指定数的所有组合
- 说你有一个数组,其中第i个元素是第i天给定股票的价格。设计一个算法来找到最大的利润,最多可以完成两个交易。
- LeetCode--找到两个排序数组中第k大的元素
- 两个排序的数组,找到第k大的元素
- 程序员面试题目总结--数组(三)【旋转数组的最小数字、旋转数组中查找指定数、两个排序数组所有元素中间值、数组中重复次数最多的数、数组中出现次数超过一半的数】
- 微软算法100题14 在排序数组中找到和为指定数的任意两个元素
- 设计一个算法找到数组中两个元素相加等于指定数的所有组合
- 在给定的数组中找出两个元素和为给定值的所有元素对
- 求两个已排序的数组中所有元素的第K大(小)
- 在给定的数组中找出两个元素和为给定值的所有元素对
- [面试题]设计一个算法找到数组中两个元素相加等于指定数的所有组合
- [面试题]设计一个算法找到数组中两个元素相加等于指定数的所有组合
- 无序数组O(n)时间找到排序后的两个相邻元素使得他们之间的差最大
- 每天一道算法题8 在排序数组中查找和为给定值的两个数字
- 14.在排序数组中查找和为给定值的两个数字
- 在一个数组中删除所有的和给定数相等的元素
- 在排序数组中寻找两个数使其和等于给定数
- 每天学习一算法系列(5)(已知两个数组,数组里的元素有正有负,但是都是按照从小到大已经排好序,要求用尽可能小的时间复杂度编写一算法求出两个数组的最大交集)
- 程序员面试题精选100题(10)-在排序数组中查找和为给定值的两个数字