题目描述 Description

给出两个有序数组A和B(从小到大有序),合并两个有序数组后新数组c也有序,询问c数组中第k大的数

假设不计入输入输出复杂度,你能否给出一个O(logN)的方法?

输入描述 Input Description

第一行输入三个整数n、m和k

第二行输入n个用空格隔开的整数表示数组A

第三行输入m个用空格隔开的整数表示数组B

输入保证A和B数组非递减

输出描述 Output Description

合并两个数组之后的第k大的数

样例输入 Sample Input

2 3 4

1  2

1 1 5

样例输出 Sample Output

2

数据范围及提示 Data Size & Hint

1<=n,m<=1000000

1<=k <=n+m

算法一:O(m+n+k)

做类似于归并排序的合并,但是没有使用额外的空间。

 #include <stdio.h>
long long n,m,k,a[],b[];
long long findKthSMallest()
{
int ai=,bi=;
while(k>)
{
if(ai<n&&bi<m)
{
if(a[ai]<=b[bi])
{
if(k==) return a[ai];
ai++;
}
else if(b[bi]<=a[ai])
{
if(k==) return b[bi];
bi++;
}
}
else if(ai<n&&bi==m)
{
if(k==) return a[ai];
ai++;
}
else if(ai==n&&bi<m)
{
if(k==) return b[bi];
bi++;
}
else return -; k--;
}
}
int main(int argc, char *argv[])
{
int i;
scanf("%d%d%d",&n,&m,&k);
for(i=;i<n;i++) scanf("%d",&a[i]);
for(i=;i<m;i++) scanf("%d",&b[i]);
printf("%d\n",findKthSMallest());
return ;
}

下面的代码是同样的思路,但是代码比较简洁易懂:

 #include <stdio.h>
int n,m,k,a[],b[];
int findKthSMallest(int a[],int n,int b[],int m,int k)
{
int a_offset = , b_offset = ;
if(n+m<k) return -; while(true)
{
if(a_offset<n)
{
while (b_offset == m || a_offset<n&&a[a_offset] <= b[b_offset])
{
if(a_offset+ + b_offset == k) return a[a_offset];
a_offset++;
}
}
if(b_offset<m)
{
while (a_offset == n || b_offset<m&&a[a_offset] >= b[b_offset])
{
if (a_offset + b_offset+ == k) return b[b_offset];
b_offset++;
}
}
}
}
int main(int argc, char *argv[])
{
int i;
scanf("%d%d%d",&n,&m,&k);
for(i=;i<n;i++) scanf("%d",&a[i]);
for(i=;i<m;i++) scanf("%d",&b[i]);
printf("%d\n",findKthSMallest(a,n,b,m,k));
return ;
}

第二段代码参考自:在线疯狂的博客,原文代码有误,已经修正。

第三种写法:省一些空间,b[ ]并没有提前完整输入。

 #include <stdio.h>
int n,m,k,a[];
int main(int argc, char *argv[])
{
int i,j,bTemp,kIndex,kValue=,f;
scanf("%d%d%d",&n,&m,&k);
for(i=;i<n;i++) scanf("%d",&a[i]); i=,kIndex=,f=;
for(j=;j<m||i<n;j++) // i是a[]的下标,j是b[]的下标
{
//for的语句条件和这里的if条件是防止b[]扫描完了却未曾寻找到第k个数.
//这个时候需要继续循环,在a[]中寻找,但是不再输入
if(j<m) scanf("%d",&bTemp); while(i<n||j<m)
{
if(j==m||i<n&&a[i]<=bTemp)
{
kIndex++;
kValue=a[i++];
if(kIndex==k) { f=; break; }
}
else
{
kIndex++;
kValue=bTemp;
if(kIndex==k) f=;
break;
}
}
if(f==) break;
}
printf("%d\n",kValue);
return ;
}

算法二:时间复杂度O(log(n+m))。当然,假如考虑输入,那时间复杂度仍然是O(n+m)

代码来源:http://www.cnblogs.com/swanspouse/p/5285015.html

代码解析:

  • 传统解法,最直观的解法是O(m+n)。直接merge两个数组,然后求第K大的数字。

  • 如果想要时间复杂度将为O(log(m+n))。我们可以考虑从K入手。如果我们每次能够删除一个一定在第K个元素之前的元素,那么我们需要进行K次,但是如果每次我们都删除一半呢?由于两个数组都是有序的,我们应该充分利用这个信息。

    • 假设A B 两数组的元素都大于K/2,我们将A B两数组的第K/2个元素进行比较。比较的结果有三种情况。

      • A[K/2] == B[K/2]
      • A[K/2] > B[K/2]
      • A[K/2] <= B[K/2]
    • 如果 A[K/2] < B[K/2] 意味着 A[0] 到 A[K/2] 肯定在A∪B的前k个元素中。因此我们可以放心删除A数组的这个k/2个元素。同理A[K/2] > B[K/2]。
    • 如果 A[K/2] == B[K/2] 说明已经找到了第K个元素,直接返回A[K/2]或者B[K/2]。
 #include <stdio.h>
#include <iostream>
using namespace std;
int a[],b[];
int find_kth(int A[],int m, int B[], int n, int k)
{
if(m > n ) return find_kth(B, n, A, m, k);
if( m == ) return B[k-];
if( k == ) return min(A[], B[]); int ia = min(k /, m);
int ib = k -ia;
if( A[ia-] < B[ib -])
return find_kth(A +ia, m -ia, B, n, k -ia);
else if( A[ia-] > B[ib-])
return find_kth(A, m, B +ib, n -ib, k -ib);
else
return A[ia-];
}
int main(int argc, char *argv[])
{
int i,n,m,k;
int ans;
scanf("%d%d%d",&n,&m,&k);
for(i=;i<n;i++) scanf("%d",&a[i]);
for(i=;i<m;i++) scanf("%d",&b[i]);
ans=find_kth(a,n,b,m,k);
printf("%d\n",ans);
return ;
}

说明

  • 注意其中的递归终止条件。
  • 将求第K大元素的问题划分成为子问题,不断的对问题进行缩小,采取递归的方式求解。
  • 此问题可以进行拓展,比如求两有序数组的中位数。

3299 有序数组合并求第K大问题的更多相关文章

  1. [CODEVS3299]有序数组合并求第K大问题

    题目描述 Description 给出两个有序数组A和B(从小到大有序),合并两个有序数组后新数组c也有序,询问c数组中第k大的数 假设不计入输入输出复杂度,你能否给出一个O(logN)的方法? 输入 ...

  2. 两个有序数组中查找第K大数

    题目:两个数组A.B,长度分别为m.n,即A(m).B(n),分别是递增数组.求第K大的数字.   方法一: 简单的办法,使用Merge Sort,首先将两个数组合并,然后在枚举查找.这个算法的时间复 ...

  3. java 有序数组合并

    有序数组合并,例如: 数组 A=[100, 89, 88, 67, 65, 34], B=[120, 110, 103, 79, 66, 35, 20] 合并后的结果 result=[120, 110 ...

  4. 两个有序数组合并成一个有序数组(要求时间复杂度为O(n))

    面试题: 怎样把两个有序数组合并成有序数组呢 逻辑步骤: 1.假设两个数组为A和B 2.A和B都是从小到大的顺序进行排列 ** 1.我们可以直接比较两个数组的首元素,哪个小就把这个小元素放入可变数组. ...

  5. Coursera Algorithms week3 快速排序 练习测验: Selection in two sorted arrays(从两个有序数组中寻找第K大元素)

    题目原文 Selection in two sorted arrays. Given two sorted arrays a[] and b[], of sizes n1 and n2, respec ...

  6. 查找两个有序数组中的第K个元素(find kth smallest element in 2 sorted arrays)

    查找两个有序数组中的第K个元素 int FindKth(int a[], int b[], int k, int astart, int aend, int bstart, int bend) { ; ...

  7. [codevs3296]有序数组合并

    题目描述 Description 合并两个有序数组A和B,使得结果依然有序. 进阶:合并两个有序数组A和B,假设A有n个数,B有m个数,A数组后面还有m个空余空间,需要将结果保存在A中. 请使用O(n ...

  8. 选取两个有序数组中最大的K个值,降序存入另一个数组中

    原题: 假设有两个有序的整型数组int *a1, int *a2,长度分别为m和n.试用C语言写出一个函数选取两个数组中最大的K个值(K可能大于m+n)写到int *a3中,保持a3降序,并返回a3实 ...

  9. HDU 6041 I Curse Myself(点双联通加集合合并求前K大) 2017多校第一场

    题意: 给出一个仙人掌图,然后求他的前K小生成树. 思路: 先给出官方题解 由于图是一个仙人掌,所以显然对于图上的每一个环都需要从环上取出一条边删掉.所以问题就变为有 M 个集合,每个集合里面都有一堆 ...

随机推荐

  1. [转]有关Apache alias的一点问题

    转自:http://www.thinkphp.cn/topic/11973.html Apache 的Alias 指令映射URL到文件系统的特定区域 一个简单的例子: Alias /mytest /w ...

  2. QT中使用MinGW 编译的protobuf库--包含库的生成和使用

    QT中使用MinGW 编译的protobuf库--包含库的生成和使用 0前言 1准备工作 2生成protobuf库文件 3在QT中测试protobuf的使用 4结语 0前言 最近要在QT中使用prot ...

  3. $.getJSON的缓存问题处理

    今天遇到jQuery.getJSON的缓存问题.如果其调用的url之前曾经调用过的话,回调函数就会直接在缓存里面取得想要得值,而不是进入到后台,调用存储过程了.这是一个比较郁闷的问题.不修改的话,用户 ...

  4. 提高sql2005中带freetexttable和rank的全文检索的速度

    原来使用中的sql2005的全文检索的速度总是不如意,尤其是带rank的.今天搜了一下,原来在freetexttable中还有一个参数top_n_by_rank,是第4个参数.注意还要设置:EXEC ...

  5. oracle的(+)

    (+)就是连接譬如SELECT a.*, b.* from a(+) = b就是一个右连接,等同于select a.*, b.* from a right join bSELECT a.*, b.* ...

  6. 大数据开发实战:离线大数据处理的主要技术--Hive,概念,SQL,Hive数据库

    1.Hive出现背景 Hive是Facebook开发并贡献给Hadoop开源社区的.它是建立在Hadoop体系架构上的一层SQL抽象,使得数据相关人员使用他们最为熟悉的SQL语言就可以进行海量数据的处 ...

  7. MFC中调用web api

    使用COM组件来调用,需要catch com error. IXMLHTTPRequestPtr pIXMLHTTPRequest = NULL; BSTR bstrString = NULL; HR ...

  8. GPUImage API文档之GLProgram类

    GLProgram是GPUImage中代表openGL ES 中的program,具有glprogram功能. 属性 @property(readwrite, nonatomic) BOOL init ...

  9. CentOS7安装Docker与使用篇

    一.在CentOS7上安装Docker篇 1. 查看系统版本: $ cat /etc/redhat-release CentOS Linux release 7.0.1406 (Core) 2. 安装 ...

  10. Xcode missing file or .png is missing from working copy

    当不小心在工程文件中删掉文件时.有可能会提示 .xxx   is missing from working copy 有可能是SVN引起的.删掉这个文件就好了 如果是单个文件.进入Terminal 相 ...