题目描述 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. [转]MCC(移动国家码)和 MNC(移动网络码)

    From : http://blog.chinaunix.net/uid-20484604-id-1941290.html     国际移动用户识别码(IMSI) international mobi ...

  2. How to delete team project from TFS visual studio ?

    /* Author: Jiangong SUN */ To delete team project from TFS Visual Studio, you need to use "TFSD ...

  3. 【虚拟化实战】Cluster设计之一资源池

    作者:范军 (Frank Fan) 新浪微博:@frankfan7 资源池是Cluster设计中的一个重要概念,本文介绍了为什么用资源池,怎么用好资源池,以及澄清了一些常见的误区. 一概念 每个ESX ...

  4. Asp.net WebAPI Ioc

    网上关于webapi Ioc 的东西很多,如http://efmvc.codeplex.com/SourceControl/latest#MyFinance.Web/Global.asax.cs 这是 ...

  5. B/S架构中常用弹出方法 (转)

    <一> 在B/S架构的项目中,为了提高项目的易用性,增强系统与用户的交互功能,一般使用弹出页面来为用户提供操作或数据选择帮助信息,比如,用户输入一个编码中某些字符,在弹出页面中显示所有包含 ...

  6. maskrcnn_benchmark代码分析(1)

    可以先参考:Faster-RCNN代码+理论——1/2 Object Detection and Classification using R-CNNs 使用ipdb调试 try: import ip ...

  7. Gson Json 序列号 最常用的功能 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  8. 泊松分布E(X^2)

    由于求期望实际就是求平均值,所以E(X^2)=E[X*X]=E[X*X]+E(X)-E(X)=E[X*X+X-X]=E[X(X-1)+X]E[X(X-1)+X]=E[X(X-1)]+E(X)即:和的平 ...

  9. Impala 数值函数大全(转载)

    官网:https://www.cloudera.com/documentation/enterprise/latest/topics/impala_math_functions.html 转载链接1: ...

  10. php7安装mongoDB扩展

    本文我们使用pecl命令来安装 首先来到php7的安装目录 $ /usr/local/php7/bin/pecl install mongodb 回车,执行成功后,会输出以下结果: …… Build ...