题目描述 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. [转]Hive安装及使用攻略

    转 : http://blog.fens.me/hadoop-hive-intro/

  2. jboss中控制台jmx-console 登录的用户名和密码设置

    默认情况访问 http://localhost:8080/jmx-console 就可以浏览jboss的部署管理的一些信息,不需要输入用户名和密码,使用起来有点安全隐患.下面我们针对此问题对jboss ...

  3. mybatis 乐观锁和逻辑删除

    本篇介绍easymybatis如配置乐观锁和逻辑删除. 乐观锁 easymybatis提供的乐观锁使用方式跟JPA一样,使用@Version注解来实现.即:数据库增加一个int或long类型字段ver ...

  4. 【MySQL】PostgresSQL-MySQL对比

    PostgresSQL-MySQL对比 (5 条消息)PostgreSQL 与 MySQL 相比,优势何在? - 知乎 IOC匹配 - 天眼公共空间 - 360企业安全Confluence 调查分析 ...

  5. ARM 汇编的mov操作立即数的疑问

    1. 因为对arm汇编有些指令还不能理解,特别是一些相似功能指令间的区别.偶然在网上搜到"faq ARM assembly",其中描述的几个问题还是值得好好研究一下. 2. 慢慢的 ...

  6. JavaScript代码不执行

    一天先后有两个同事问我为啥他的js代码出现了莫名其妙的问题 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "h ...

  7. [Functional Programming] Daggy

    const daggy = require('daggy'); const {tagged, taggedSum} = daggy; const Coord = daggy.tagged('Coord ...

  8. hdu 5411 CRB and Puzzle (矩阵高速幂优化dp)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5411 题意:按题目转化的意思是,给定N和M,再给出一些边(u,v)表示u和v是连通的,问走0,1,2... ...

  9. mysql生成不重复随机数(unique number generation)

    转自:http://blog.csdn.net/dreamer2020/article/details/52049629 问题来源 业务中有时会遇到要生成不重复随机数的情况,例如,新生成一个商品编号. ...

  10. jquery效果 窗口弹出案例

    效果 ①基本效果:show().hide().toggle() ②滑动 slideDown().slideUp().slideToggle() 划上:$("p").slideUp( ...