algorithm@ find kth smallest element in sorted arrays (O (log n time)

Source: Internet
Author: User

the trivial, 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 t O readers who suggested this. (See comments below by martin for an implementation). Using The pointers, you can traverse both arrays without actually merging them, thus without the extra space. Both pointers is initialized to point-to-head of A and B respectively, and the pointer that have The larger   finding intersection of the sorted arrays.

the best solution, but non-trivial,  O (lg  m  + lg  n ):
Although the above solution is a improvement both in run time and space complexity, it only works 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 it search space in each iteration. Therefore, to achieve the complexity of O (LG  m   + lg  n ), we must halved the Searc H space of A and B in each iteration.

We try to approach the 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 i + j = k - 1 that, we is able to find the k-th smallest element. This is a 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 is the k-th smallest,
Or else if Ai-1 < BJ < Ai, then Bj must is the k-th smallest.

If one of the above conditions is satisfied, we is done. If not, we'll useIandJAs the pivot index to subdivide the arrays. But how? Which portion should we discard? How about Ai and Bj itself?

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

Using The above relationship, it becomes clear when Ai < Bj, AI and its lower portion could never is the k-th smal Lest element. So does BJ and its upper portion. Therefore, we could conveniently discard Ai with its lower portion and BJ with its upper portion.

If you were still not convince why the above argument was true, try drawing blocks representing elements in A and B. Try Vis Ualize inserting blocks of A up to Ai in front of Bj-1. You could easily see this no elements in the inserted blocks would ever is the k-th smallest. For the latter, your might want to keep the invariantI+J=k-1 in mind to reason why Bj and its upper portion could never is the k-th smallest.

On the other hand, the case for Ai > Bj are just the other to the around. Easy.

Below is the code and I had inserted lots of assertion (highly recommended programming style by the The) Rstand the code. Note that the below code was 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 what I derive the solution and it seemed more natural to being expressed in A recursive manner.

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

intFindkthsmallest (intA[],intMintB[],intNintk) {assert (M>=0); ASSERT (n >=0); ASSERT (K >0); Assert (k <= m+N); inti = (int)((Double) m/(m+n) * (K-1)); intj = (K-1) -i; ASSERT (I>=0); ASSERT (J >=0); ASSERT (I <= m); ASSERT (J <=N); //invariant:i + j = k-1//Note:a[-1] =-inf and a[m] = +inf to maintain invariant    intAi_1 = ((i = =0) ? int_min:a[i-1]); intBj_1 = ((j = =0) ? int_min:b[j-1]); intAi = ((i = = m)?Int_max:a[i]); intBj = ((j = = N)?Int_max:b[j]); if(Bj_1 < AI && ai <Bj)returnAi; Else if(Ai_1 < BJ && BJ <Ai)returnBj; 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        returnFindkthsmallest (a+i+1, m-i-1, B, J, k-i-1); Else /*Bj < Ai*/        //exclude Ai and above portion//exclude Bj and below portion        returnFindkthsmallest (A, I, b+j+1, n-j-1, k-j-1);}

[email protected] find kth smallest element in sorted arrays (O (log n time)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.