http://www.cnblogs.com/buptLizer/archive/2012/03/31/2427579.html

给出两个排好序的数组 ,不妨设为a,b都按升序排列,及k的值,求出第k大的那个元素。

分析这个题目,如果题目没有时间复杂度的要求,我们可以定义两个指针i,j分别指向a,b,如果a[i]<b[j]则i++否则

j++,这个记录下走了多少步,如果==k步,则找到了第k大的元素,复杂度为O(k).

那么如果有复杂度的要求,要求为O(log(len_a+len_b))呢,这个就得好好考虑,怎么利用二分来解决这个问题。

判断a[mid_a] 与 b[mid_b]的关系
 如果a[mida] < b[mid_b]

1)k小于等于mida + midb + 1,那么b数组从mid_b开始就没有用了,缩小b的搜索范围
 2)k大于mida + midb + 1, 那么a数组从low到mid_a开始就没用了,缩小a的搜索范围
 3)终止条件是 a搜索完 返回b中元素或者相反

int get_k_from_sorted_array2(int* a, int*b, int la, int ha, int lb, int hb, int k)
{if(la > ha)return b[lb + k - 1];if(lb > hb)return a[la + k - 1];int mida = (la + ha)>>1;int midb = (lb + hb)>>1;int num = mida- la + midb - lb + 1;cout<<la<<" "<<ha<<" "<<lb<<" "<<hb<<" "<<num<<" "<<a[mida]<<" "<<b[midb]<<endl;if(a[mida] <= b[midb]){if(k <= num)return get_k_from_sorted_array2(a, b, la, ha, lb, midb - 1, k);elsereturn get_k_from_sorted_array2(a, b, mida + 1, ha, lb, hb, k - (mida - la + 1));}else{if(k <= num)return get_k_from_sorted_array2(a, b, la, mida - 1, lb, hb, k);elsereturn get_k_from_sorted_array2(a, b, la, ha, midb + 1, hb, k - (midb - lb + 1));}
}
int _func2(int* a, int a_len, int* b, int b_len, int k)
{int rst = 0;if(a_len + b_len < k)return -1;int p1 = a_len > k ? k : a_len;int p2 = b_len > k ? k : b_len;cout<<p1<<" "<<p2<<endl;rst = get_k_from_sorted_array2(a, b, 0, p1 - 1, 0, p2 - 1, k);return rst;
}

还有更霸气的解答:

http://blog.csdn.net/beiyeqingteng/article/details/7533304

前言:

这道题是一道非常常见的面试题,也是一道能够考察一个人的编程能力和算法的一道题。如果要求复杂度为 O(k), 是比较容易做出来的,但是,一般来讲,面试官要求给出更低复杂度的算法。网上有很多不同的解法,但是,总的来讲,那些程序考虑的因素太多,比较难懂,而且结构很乱。在这里写出自己的方法。本文的算法复杂度为 O(lg K)。

PS. 如果你没有见过这个题目,并且能够在30分钟内写出没有bug的,复杂度为 O(lg K) 的程序,我愿意拜你为师,呵呵。

问题:

给定两个已经排序的数组(假设按照升序排列),然后找出第K小的数。比如数组A = {1, 8, 10, 20}, B = {5, 9, 22, 110}, 第 3 小的数是 8.

分析:

### 最好自己先动手写一写,然后再看后面的分析,因为自己写过一遍以后,才能发现这个程序的难处在哪里。###

因为两个数组已经排序了,所以,要找出第 k 小的值,我们可以给每个数组设置一个“指针”, 比如pa, pb。在初始状态,两个指针分别指向第一个起始值,即pa = 0, pb = 0。然后,我们开始进行比较,如果A数组的值比B数组的值小, 把A数组的指针pa向前移动,然后再进行比较。每次移动,我们都能够得到当前第 i 小的值(随着pa,pb 的移动,i 会逐渐变大)。

比如对于数组A = {1, 8, 10, 20}, B = {5, 9, 22, 110},初始时,pa = 0; pb = 0,因为(A[pa] = 1) < (B[pb] = 5), 所以,第 1 小的值为 1,这个时候,我们会把 pa 向右移动,即 pa = 1, 并且 pb 保持不变: pb = 0. 然后再次比较A[pa] 和 B[pb] 的值,因为  (A[pa] = 8) > (B[pb] = 5), 所以,第 2 小的值是 5, 然后,我们增加 pb 的值。请注意,如果我们用一个变量来保存当前第 i 小的值 (随着pa, pb的移动,i 的值也会增加,那个变量保存的值也会改变)。那么,当pa + pb = k 的时候,那么那个变量保存的一定是第 k 小的值

这里要注意的是,当一个数组的指针已经“到头”了,这个时候怎么进行越界处理呢?如果我们用if 来处理,在程序里会有一大堆的 if 判断语句,太难看了。我们这里可以用一个简单的判断语句就可以处理了。

[java] view plaincopy
  1. int Ai = (pa == A.length) ? Integer.MAX_VALUE : A[pa];
  2. int Bj = (pb == B.length) ? Integer.MAX_VALUE : B[pb];

(上面这个语句太牛逼了,但很可惜不是我自己写的,这是向人家学的。)有了这个语句,我们不用任何if语句,而且, 最最重要的是,我们可以从一开始就用这个语句来确定A[pa]和B[pb]的值,所以,从头到尾,不会有任何的改变,也不会有越界的情况出现(为何不会越界?看完后面的代码就知道了。) 。

好了,有了上面的分析,下面的代码就不难理解了。

[java] view plaincopy
  1. public static int kthTwoSortedArray(int[] A, int[] B, int k) throws Exception {
  2. if (k > A.length + A.length || k < 1) throw new Exception("out of range!");
  3. // pointer of array A
  4. int pa = 0;
  5. // pointer of array B
  6. int pb = 0;
  7. //store the kth value
  8. int kthValue = 0;
  9. while (pa + pb != k) {
  10. int Ai = (pa == A.length) ? Integer.MAX_VALUE : A[pa];
  11. int Bj = (pb == B.length) ? Integer.MAX_VALUE : B[pb];
  12. if (Ai < Bj) {
  13. pa++;
  14. kthValue = Ai;
  15. } else {
  16. pb++;
  17. kthValue = Bj;
  18. }
  19. }
  20. return kthValue;
  21. }

上面这个程序的复杂度是O(k),分析很简单,就不再讲了。

现在再来看如何得到 O(lg K) 的算法。

在上面的程序里,我们是逐一比较数组A 和数组B的值,但是,这样做还是太慢了,因为两个数组是已经排过序的,我们完全可以利用二分查找的方法来解决这样的问题。但是具体介绍怎么做之前,先讲一些预备知识。

对于数组A 、 B , 如果 B[pb] < A[pa] && B[pb] > A[pa - 1], 那么 B[pb] 一定是第 pa + pb + 1  小的数。 比如数组A = {1, 8, 10, 20}, B = {5, 9, 22, 110}, pa = 2, pb = 1, 这时,(B[pb] = 9) < (A[pa] =10) && (B[pb] = 9) > (A[pa - 1] = 8) ,那么,B[pb] = 9 一定是第 pa+pb+1 = 4 小的数。 换一句话说,如果我们要找第 k 小的数,那么, pa + pb  = k - 1。而且,B[pb] < A[pa] && B[pb] > A[pa - 1] 或者 A[pa] < B[pb] && A[pa] > B[pb - 1] 中的其中一个必须成立。 如果不成立, 我们需要移动pa 和 pb 的位置来使得其中的一个式子成立 (参看代码)。这是本题算法的本质。

但是,这里也会出现”边界“问题,比如,k = 1, 那么 pa + pb  = 1 - 1, 即 pa + pb = 0. 因为 pa >= 0, pb >=0, 所以,我们得到 pa = 0, pb = 0. 那么这样的话, 求A [pa-1]值的时候 就会有exception. 同理,对于数组A = {1, 8, 10, 20}, B = {5, 9, 22, 110},当k = 8 的时候, pa + pb  = 8 - 1, 即 pa + pb = 7, 但是,pa <= 3, pb <= 3。边界的处理是这道题最最麻烦的地方。对于这个问题,我们用下面这段代码来解决。

[java] view plaincopy
  1. int Ai_1 = (pa == 0) ? Integer.MIN_VALUE : A[pa-1];
  2. int Bj_1 = (pb == 0) ? Integer.MIN_VALUE : B[pb-1];
  3. int Ai   = (pa == A.length) ? Integer.MAX_VALUE : A[pa];
  4. int Bj   = (pb == B.length) ? Integer.MAX_VALUE : B[pb];

通过上面这段代码,我们实际上是把数组延长了,每个数组多了两个值Integer.MIN_VALUE, Integer.MAX_VALUE, 这样,当pa = 0 是,我们也可以得到A[pa - 1] 的值:Ai_1 = ((pa == 0) ? Integer.MIN_VALUE : A[pa-1]); 当 pa =  A.length 时,我们可以得到 A[pa]的值:Ai = (pa == A.length) ? Integer.MAX_VALUE : A[pa]。 这样,我们就不用担心越界的问题了。

有了上面的分析,代码就容易写出来了。

在程序里,我们设置 pa 的初始值为Math.min(A.length, k - 1),然后,通过增加或者减少pa 的值,来使得 B[pb] < A[pa] && B[pb] > A[pa - 1] 或者 A[pa] < B[pb] && A[pa] > B[pb - 1]  成立,代码中, delta 指的是 pa 的变化量,每次递归以后,delta的值变成一半。 在程序中用delta完成二分查找

public class FindKthSmallestValue {public static int findKthSmallest(int[] A, int[] B, int pa, int delta, int k) {int pb = (k - 1) - pa;//保证pb+ba = k -1int Ai_1 = ((pa == 0) ? Integer.MIN_VALUE : A[pa-1]);int Bj_1 = ((pb == 0) ? Integer.MIN_VALUE : B[pb-1]);int Ai   = ((pa == A.length) ? Integer.MAX_VALUE : A[pa]);int Bj   = ((pb == B.length) ? Integer.MAX_VALUE : B[pb]);//满足其中之一条件,就返回if (Bj_1 <= Ai && Ai <= Bj) return Ai;if (Ai_1 <= Bj && Bj <= Ai) return Bj;//delta表示pa的变化量(pa通过加减delta实现pa的增加或者减少)//如果 Ai > Bj, 我们要缩小pa的值,即 pa = pa - delta//因为 pb = (k - 1) - pa, 所以,如果delta的值太大,//pa会变得很小,因而 可能会导致 pb > B.length. 所以需要处理一下。// 对于pa = pa + delta 的处理也是一样if (Ai > Bj) {pa = ((k - 1) - (pa - delta) > B.length) ? k - 1 - B.length : pa - delta;//防止把pa调整的过小,而导致pb+pa<k-1return findKthSmallest(A, B, pa, (delta + 1) / 2, k);} else {pa = (pa + delta > A.length) ? A.length : pa + delta;return findKthSmallest(A, B, pa, (delta + 1) / 2, k);            }}public static void main(String[] args) {int[] A = {1, 8, 8, 10, 20};int[] B = {5, 8, 8, 9, 22, 110};int k = 7;int pa = Math.min(A.length, k - 1);System.out.println(findKthSmallest(A, B, pa, (pa + 1) / 2, k));}
}

查找两个已经排好序的数组的第k大的元素相关推荐

  1. python第k序列元素查找_【python】寻找数组中第k大的元素

    题目链接:https://www.nowcoder.com/question/next?pid=13956292&qid=298692&tid=26431616 方法一: 最简单直接的 ...

  2. 在两个已经排好序的数组里找出第K小的数

    前言: 这道题是一道非常常见的面试题,也是一道能够考察一个人的编程能力和算法的一道题.如果要求复杂度为 O(k), 是比较容易做出来的,但是,一般来讲,面试官要求给出更低复杂度的算法.网上有很多不同的 ...

  3. 合并两个已经排好序的不等长的数组

    给两个已经排好序的数组.这两个数组的长度可能不相等.怎样将他们合并? package airth;public class TestMergeArray {/*** 功能:* 作者: jiangfuq ...

  4. 两个服务器 文件比较,使用linux的comm命令比较两个已排过序的文件

    使用linux的comm命令比较两个已排过序的文件 发布时间:2020-07-09 10:41:42 来源:亿速云 阅读:55 作者:清晨 栏目:服务器 这篇文章主要介绍使用linux的comm命令比 ...

  5. C语言,往排好序的数组中插入元素

    例题:有一个已经排好序的数组,元素分别是:1,3,5,7,9,从键盘上输入一个元素,将这个元素插入到数组中,使数组仍保持从小到大排序. 输出时各元素的最小宽度为5. 例: (1)输入:0  输出:   ...

  6. Python Challenge-39 有一个已经排好序的数组。现输入一个数,要求按原来的规律将它插入数组中。

    #题目:有一个已经排好序的数组.现输入一个数,要求按原来的规律将它插入数组中. #!/usr/bin/python 3 # -*- coding: UTF-8 -*- #两种方法_Author_ = ...

  7. c语言:“有一个已排好序的数组,要求输入一个数后,按原来的规律将它插入数组中” 的程序分析及详细代码

    先来分析思路: 已经排好序的数组,有两种情况,一种是顺序,一种是逆序,由于该数组是自己给出的,所以我们不妨将该数组的顺序设为顺序. 1.我们需要创建一个顺序数组(a[ ]),创建时要注意,我们要确保数 ...

  8. 有一个已排好序的数组,要求输入一个数后,按原来排序的规律将它插入数组中,谭浩强《c语言程序设计》第六章第四题

    题目 本题是谭浩强<c语言程序设计>第六章第四题 题目:有一个已排好序的数组,要求输入一个数后,按原来排序的规律将它插入数组中. 以下是本篇文章正文内容,欢迎朋友们进行指正,一起探讨,共同 ...

  9. java数组:排好序的数组。现输入一个数,要求按原来的规律将它插入数组中。`

    有一个已经排好序的数组.现输入一个数,要求按原来的规律将它插入数组中. 程序分析:首先判断此数是否大于最后一个数,然后再考虑插入中间的数的情况,插入后此元素之后的数,依次后移一个位置` public ...

最新文章

  1. IOS-开发日志-UILabel相关
  2. 深度学习在搜索和推荐领域的应用
  3. phpcms漏洞总结
  4. 四大开源无人机项目,极客要Get了
  5. virsh 关机_kvm 虚拟化 virsh shutdown 无法关闭虚拟机
  6. Windows开机运行程序
  7. 去空格函数trim-C语言
  8. 2022年6月青少年软件编程(Python)等级考试试卷(一级)
  9. vscode顶部菜单栏不见了,怎么办?
  10. java 克隆对象_Java中克隆(Clone)一个对象
  11. Centos 查看 CPU 核数 和 型号 和 主频
  12. PCI-PCIE中断机制之一
  13. JAVA面试题整理2020
  14. OpenJudge百炼-2745-显示器-C语言-模拟
  15. 计算机桌面内存,电脑内存怎么清理
  16. 微信之父张小龙的2359篇日记
  17. Nett源码剖析(2)NioEventloopGroup的创建2021SC@SDUSC
  18. 网络传播时延(propagation delay)与传输时延(transmission delay)
  19. 【GO+Iris】Iris框架初识
  20. html橙光游戏制作工具,橙光游戏制作工具全部视频教程

热门文章

  1. 降低百倍时间步,精度媲美传统神经网络:上交等机构提出ANN-SNN转换框架
  2. 博士申请 | 澳大利亚悉尼科技大学招收人工智能/软件工程方向全奖博士生
  3. 今日arXiv精选 | 12篇EMNLP 2021最新论文
  4. 清华大学高阳:Mastering Atari Games with Limited Data
  5. 预训练语言模型论文分类整理:综述、基准数据集、PLM的设计和分析
  6. 直播 | WWW 2021:用先验知识指导BERT注意力机制的语义文本匹配
  7. 胶囊网络(Capsule Network)在文本分类中的探索
  8. 【教程】Jupyter notebook基本使用教程
  9. IntelliJ IDEA安装
  10. linux 消息对lie_Linux进程间通信之消息队列总结