Two sorted arrays are given. We have to find the K smallest products from the pairs from these arrays. I could think of a mnlogk solution but this solution works ev
Instead of using the heap, try to generate products in the sorted order.
Imagine an n*m
grid formed by indices into the respective arrays. At any given point of time the grid is partitioned into the "inspected" and "not yet inspected" parts. We shall keep an invariant, namely that a product of every inspected pair is less than the product of a not inspected. The hard part is to prove that the border separating them has O(n+m)
pairs; the fact that the arrays are sorted is essential for the proof.
Now, you may test the products along the border, take the minimal, and modify the border accordingly. This operation will take O(n+m)
time, and would be performed k
times. An overall complexity is O(k(n+m)
).
And the final optimization: the above plan recomputes many products along the border over and over again. Representing the border as a sorted map may drive the complexity down to O(k log(n+m))
.
Here is an algorithm that has O(k min(n, m)) time complexity.
Let A and B be sorted lists of integers, i.e. A = [a1 a2 a3 ... am] with ai ≤ ai+1, and B = [b1 b2 b3 ... bn] with bi ≤ bi+1.
Assume for now that ai ≥ 0 and bi ≥ 0. We will show below how to account for negative integers.
Let p = (i j) be a pair, where i and j are the indexes of ai and bj. Let P be a list of pairs. Set P = [(1 1) (1 2) (1 3) ... (1 n)]. Assume k > 0 (and k ≤ m x n). Let R be the list of the pairs of the k first products. Initialize R = [].
Add the first pair p = (i j) of P to R.
If R is of size k, terminate.
Set p = (i+1 j). While the product of p is greater than the product of the next pair q in P, exchange p and q.
Go to step 1.
The above algorithm has time complexity O(k n) and works for A and B containing non-negative integers only. Note that if m < n, we can exchange A and B to get a lower bound on the time complexity.
Here is an example that illustrates the algorithm with A = [2 6 13] and B = [1 6 9]. The matrix below shows the product ai x bj for every (i j).
B 1 6 9
A ------------
2 | 2 12 18
6 | 6 36 54
13 | 13 78 117
This is the initial states of P and R at the start of the alogrithm. We suffix each pair (i j) in P with the value of the product ai x bj.
P = [(1 1):2 (1 2):12 (1 3):18] R = []
On the first iteration, (1 1):2
is added to R, and the first pair in P becomes (1+1 1)
.
R = [(1 1):2]
P = [(2 1):6 (1 2):12 (1 3):18]
On the next iteration, (2 1):6
is added to R, and the first pair in P becomes (2+1 1)
. Because the product of that pair is greater than the product of the next pair in P, they are exchanged.
R = [(1 1):2 (2 1):6]
P = [(3 1):13 (1 2):12 (1 3):18]
P = [(1 2):12 (3 1):13 (1 3):18]
Next iteration, similar operations as the previous iteration.
R = [(1 1):2 (2 1):6 (1 2):12]
P = [(2 2):36 (3 1):13 (1 3):18]
P = [(3 1):13 (1 3):18 (2 2):36]
In this iteration, after adding (3 1):13
to R, the first pair of P becomes (3+1 1)
, but that pair does not exist. So, it is simply removed from P.
R = [(1 1):2 (2 1):6 (1 2):12 (3 1):13]
P = [(1 3):18 (2 2):36]
Following are all remaining iterations until P is empty.
R = [(1 1):2 (2 1):6 (1 2):12 (3 1):13 (1 3):18]
P = [(2 3):54 (2 2):36]
P = [(2 2):36 (2 3):54]
R = [(1 1):2 (2 1):6 (1 2):12 (3 1):13 (1 3):18 (2 2):36]
P = [(3 2):78 (2 3):54]
P = [(2 3):54 (3 2):78]
R = [(1 1):2 (2 1):6 (1 2):12 (3 1):13 (1 3):18 (2 2):36 (2 3):54]
P = [(3 3):117 (3 2):78]
P = [(3 2):78 (3 3):117]
R = [(1 1):2 (2 1):6 (1 2):12 (3 1):13 (1 3):18 (2 2):36 (2 3):54 (3 2):78]
P = [(3 3):117]
R = [(1 1):2 (2 1):6 (1 2):12 (3 1):13 (1 3):18 (2 2):36 (2 3):54 (3 2):78 (3 3):117]
P = []
Now, if A and B contain both non-negative and negative integers, we can use the above algorithm to solve at most 4 sub-problems concurrently to get the k smallest integers. For this, we define the iterator function F(A, B) that on each call yields the next product in increasing order using the above algorithm. Let A- and A+ be the sublists of A containing its negative and non-negative integers respectively. Same thing for B- and B+. We call our iterator function for the following 4 sub-problems.
F(A+, B+)
F(A+, reverse(B-))
F(reverse(A-), B+)
F(reverse(A-), reverse(B-))
where reverse(L) returns list L with its elements in reverse order. We iterate over these four iterators choosing the k smallest returned pairs.