The trivial way, O(m + n):
Merge both arrays and the k-th smallest element could be accessed directly. Merging would require extra space of O(m+n). The linear run time is pretty good, but could we improve it even further?

A better way, O(k):
There is an improvement from the above method, thanks to readers who suggested this. (See comments below by Martin for an implementation). Using two pointers, you can traverse both arrays without actually merging them, thus without the extra space. Both pointers are initialized to point to head of A and B respectively, and the pointer that has the larger finding intersection of two sorted arrays.

The best solution, but non-trivial, O(lg m + lg n):
Although the above solution is an improvement both in run time and space complexity, it only works well for small values of k, and thus is still in linear run time. Could we improve the run time further?

The above logarithmic complexity gives us one important hint. Binary search is a great example of achieving logarithmic complexity by halving its search space in each iteration. Therefore, to achieve the complexity ofO(lg m  + lg n), we must halved the search space of A and B in each iteration.

We try to approach this tricky problem by comparing middle elements of A and B, which we identify as Ai and Bj. If Ai is between Bj and Bj-1, we have just found the i + j< + 1 smallest element. Why? Therefore, if we choose i and j such that i + j = k - 1, we are able to find the k-th smallest element. This is an important invariant that we must maintain for the correctness of this algorithm.

Summarizing the above,

Maintaining the invariant
    i j = k - 1,

If Bj-1 < Ai < Bj, then Ai must be the k-th smallest,
or else if Ai-1 < Bj < Ai, then Bj must be the k-th smallest.

If one of the above conditions are satisfied, we are done. If not, we will use i and j as the pivot index to subdivide the arrays. But how? Which portion should we discard? How about Ai and Bj itself?

We make an observation that when Ai < Bj, then it must be true that Ai < Bj-1. On the other hand, if Bj < Ai, then Bj < Ai-1. Why?

Using the above relationship, it becomes clear that when Ai < Bj, Ai and its lower portion could never be the k-th smallest element. So do Bj and its upper portion. Therefore, we could conveniently discard Ai with its lower portion and Bj with its upper portion.

If you are still not convince why the above argument is true, try drawing blocks representing elements in A and B. Try visualize inserting blocks of A up to Ai in front of Bj-1. You could easily see that no elements in the inserted blocks would ever be the k-th smallest. For the latter, you might want to keep the invariant i + j = k - 1 in mind to reason why Bj and its upper portion could never be the k-th smallest.

On the other hand, the case for Ai > Bj is just the other way around. Easy.

Below is the code and I have inserted lots of assertion (highly recommended programming style by the way) to help you understand the code. Note that the below code is an example of tail recursion, so you could technically convert it to an iterative method in a straightforward manner. However, I would leave it as it is, since this is how I derive the solution and it seemed more natural to be expressed in a recursive manner.

Another side note is regarding the choices of i and j. The below code would subdivide both arrays using its array sizes as weights. The reason is it might be able to guess the k-th element quicker (as long as the A and B is not differed in an extreme way; ie, all elements in A are smaller than B). If you are wondering, yes, you could choose i to be A's middle. In theory, you could choose any values for i and j as long as the invariant i+j = k-1 is satisfied.

int findKthSmallest(int A[], int m, int B[], int n, int k) {
assert(m >= ); assert(n >= ); assert(k > ); assert(k <= m+n); int i = (int)((double)m / (m+n) * (k-));
int j = (k-) - i; assert(i >= ); assert(j >= ); assert(i <= m); assert(j <= n);
// invariant: i + j = k-1
// Note: A[-1] = -INF and A[m] = +INF to maintain invariant
int Ai_1 = ((i == ) ? INT_MIN : A[i-]);
int Bj_1 = ((j == ) ? INT_MIN : B[j-]);
int Ai = ((i == m) ? INT_MAX : A[i]);
int Bj = ((j == n) ? INT_MAX : B[j]); if (Bj_1 < Ai && Ai < Bj)
return Ai;
else if (Ai_1 < Bj && Bj < Ai)
return Bj; assert((Ai > Bj && Ai_1 > Bj) ||
(Ai < Bj && Ai < Bj_1)); // if none of the cases above, then it is either:
if (Ai < Bj)
// exclude Ai and below portion
// exclude Bj and above portion
return findKthSmallest(A+i+, m-i-, B, j, k-i-);
else /* Bj < Ai */
// exclude Ai and above portion
// exclude Bj and below portion
return findKthSmallest(A, i, B+j+, n-j-, k-j-);
}

algorithm@ find kth smallest element in two sorted arrays (O(log n time)的更多相关文章

  1. 查找两个有序数组中的第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) { ; ...

  2. Leetcode:378. Kth Smallest Element in a Sorted Matrix

    题目: Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the ...

  3. [LeetCode] Kth Smallest Element in a Sorted Matrix 有序矩阵中第K小的元素

    Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth ...

  4. 378. Kth Smallest Element in a Sorted Matrix

    Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth ...

  5. Leetcode: Kth Smallest Element in a Sorted Matrix

    Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth ...

  6. [Swift]LeetCode378. 有序矩阵中第K小的元素 | Kth Smallest Element in a Sorted Matrix

    Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth ...

  7. 【Leetcode】378. Kth Smallest Element in a Sorted Matrix

    Question: Given a n x n matrix where each of the rows and columns are sorted in ascending order, fin ...

  8. Kth Smallest Element in a Sorted Matrix -- LeetCode

    Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth ...

  9. leetcode_378. Kth Smallest Element in a Sorted Matrix_堆的应用

    Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth ...

随机推荐

  1. 如何助力企业 APP 在竞争中占据先机?

    做好产品的六字真言:刚需.痛点.高频 --周鸿祎 好的产品是需要不断打磨的.在开发任何产品之前,都需要进行严格的假设和调研,找到刚需,找到痛点.然后就是不断的验证自己的假设,不断地在适当的试错过程中成 ...

  2. RASP 完爆 WAF 的5大理由!

    Web 应用防火墙(WAF)已经成为常见 Web 应用普遍采用的安全防护工具,即便如此,WAF 提供的保护方案仍旧存在诸多不足,笔者认为称 WAF 为好的安全监控工具更为恰当.幸运的是,应用安全保护技 ...

  3. JAVA面试题:String 堆内存和栈内存

    java把内存划分为两种:一种是栈(stack)内存,一种是堆(heap)内存 在函数中定义的一些基本类型的变量和对象的引用变量都在栈内存中分配,当在一段代码块定义一个变量时,java就在栈中为这个变 ...

  4. hdu 4655 Cut Pieces

    这个解题报告讲的很详细了!!! 代码如下: #include<iostream> #include<stdio.h> #include<algorithm> #in ...

  5. highcharts 多数据+切换

    var highchartsOptions = { chart:{ renderTo:'container' }, title:{ text:'指标数据' }, tooltip:{ pointForm ...

  6. Android_Mars学习笔记_S01_001activity初步

    一.activity初步 1.程序启动会先读配置文件AndroidManifest.xml找activity 2.activity会在onCreate方法中读取activity_main.xml文件, ...

  7. 屏蔽QQ聊天对话框中的广告

    原文地址: 怎么在QQ聊天对话框中屏蔽广告_百度经验 http://jingyan.baidu.com/article/48a42057ca12c1a924250402.html     QQ已经成为 ...

  8. CityEngine 2013部署安装

    安装环境: windows8.1 专业版 已安装arcgis10.2 2的授权方式也同样分为:单机许可和浮动 许可.单机许可是将许可部署在本机直接使用:浮动许可是部署到服务器上通过IP地址连接,可借出 ...

  9. POJ2109——Power of Cryptography

    Power of Cryptography DescriptionCurrent work in cryptography involves (among other things) large pr ...

  10. CodeIgniter类库之Benchmarking Class ,计算代码的执行时间

    CodeIgniter中有个Benchmarking类库,它是被系统自动被加载的,不需要手工加载.Benchmarking类库能够计算出任意两个被标记点之间的代码执行时间.通过这个数值,可以评估程序员 ...