题目描述 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. mac或者linux磁力下载方法:远离渣雷

    wget是linux下常用的命令行下载工具,是Linux用户是必不可少的工具,尤其对于网络管理员,经常要下载一些软件. t-get是一个简单的命令行BT下载工具,可以用于BT种子和磁力链接的下载 tg ...

  2. Http请求中Content-Type讲解以及在Spring MVC注解中produce和consumes配置详解

    原文地址:  https://blog.csdn.net/shinebar/article/details/54408020 引言: 在Http请求中,我们每天都在使用Content-type来指定不 ...

  3. 第一章 第一个dubbo项目

    为了安全:服务启动的ip全部使用10.10.10.10 版本: dubbo:2.5.5 重要的网址: dubbo的github:https://github.com/alibaba/dubbo dub ...

  4. go语言之进阶篇接口的继承

    1.接口的继承 示例: package main import "fmt" type Humaner interface { //子集 sayhi() } type Persone ...

  5. easyui datagrid列使用按钮的一些心得 .

    以前,用easyui的datagrid,有时候会用到一些操作选项,比如代码如下: $('#datagrid').datagrid({ border:false, fitColumns:true, si ...

  6. 微信公众号网页授权获取用户openid

    最近一个项目是在微信公众号内二次开发,涉及到微信公众号支付,根据文档要求想要支付就必须要获取到用户的openid. 这是微信官方文档https://mp.weixin.qq.com/wiki?t=re ...

  7. 关于UI设计中的交互软件Axure7.0运用

    Axure RP是一个专业的快速原型设计工具.让负责定义需求和规格.设计功能和界面的人员能够快速创建应用软件或Web网站的线框图.流程图.原型和规格说明文档. 作为专业的原型设计工具,它能快速.高效的 ...

  8. DaoCloud加速docker镜像下载

    1. 注册DaoCloud用户; 2. 注册完成后,会进入dashboard页面,点击右上方的加速器.该页面提供了Linux.Windows和Mac的加速方案,我这里选择的是Linux: 3. 执行其 ...

  9. Discuz!X/数据库操作方法

    原DB类的改进 Discuz! X2.5新版对数据库DB层进行了功能和安全方面的加强: addslashes的处理 仅insert(),update(),delete() 方法对传入其的数组形式的参数 ...

  10. 【转】开发者可以使用Docker做什么?

    有些开发者可能还是不明白 Docker 对自己到底有多大的用处,因此翻译 Docker 个人用例 这篇文章中来介绍 Docker 在普通开发者开发过程中的用例. Docker 如今赢得了许多关注,很多 ...