题目描述 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. Unit Testing of Spring MVC Controllers: Configuration

    Original Link: http://www.petrikainulainen.net/programming/spring-framework/unit-testing-of-spring-m ...

  2. org.codehaus.jackson.map.JsonMappingException: Can not construct instance of java.util.Date from String value '2012-12-12 12:01:01': not a valid representation (error: Can not parse date "2012-12-

    Jackson对于date的反序列化只支持几种,如果不符合默认格式则会报一下错误 org.codehaus.jackson.map.JsonMappingException: Can not cons ...

  3. JAVA的Split小技巧

    在日常的开发中截取字符串必不可少,但是在JAVA中的Split截取有点特点的地方是         例如:            String str=1,2,3,; 那么  str.split(&q ...

  4. jQuery对象

    $(document).ready(function(){ //第二种获取方法,通过标签的名<h2>Dom来获取 var h1 = document.getElementsByTagNam ...

  5. [Algorithm] Delete a node from Binary Search Tree

    The solution for the problem can be divided into three cases: case 1: if the delete node is leaf nod ...

  6. Code optimization and organization in Javascript / jQuery

    This article is a combined effort of Innofied Javascript developers Puja Deora and Subhajit Ghosh) W ...

  7. C# 动态解析表达式

    需求 我们很难捉摸用户的思维,即使使用非常正式的文档规范某些数据的定义.结果的标准等,也不能抵挡住用户不断变化的需求,但他们有个万变不离的东西——你做这个东西要是万能的,即输入参数类型.个数等发生改变 ...

  8. UIFont字体大全

    原文地址:UIFont 设置字体作者:青竹居士     http://deep-fish.iteye.com/blog/1678874UIFont 设置字体 1 label.font = [UIFon ...

  9. 微信小程序 - 分包加载(预下载)

    开发者可以通过配置,在进入小程序某个页面时,由框架自动预下载可能需要的分包,提升进入后续分包页面时的启动速度.对于独立分包,也可以预下载主包. 配置方法 预下载分包行为在进入某个页面时触发,通过在 a ...

  10. 在CentOS7(虚拟机)下通过源码安装Postgresql10以及基本配置

    操作系统:CentOS7 安装文件:postgresql-10.0.tar.gz 系统环境:gcc.Python 1:源码安装 [postgres@localhost ~]# tar zxvf pos ...