tags:

views:

96

answers:

2

We have three sets S1, S2, S3. I need to find x,y,z such that x E S1 y E S2 z E S3

let min denote the minimum value out of x,y,z let max denote the maximum value out of x,y,z The range denoted by max-min should be the MINIMUM possible value

+3  A: 
min = infinity (really large number in practice, like 1000000000)
solution = (-, -, -)
for each x E S1
    for each y E S2
        for each z E S3
            t = max(x, y, z) - min(x, y, z)
            if t < min
                min = t
                solution = (x, y, z)
IVlad
This algorithm gives the solution O(N^3) is there anything that gives a beter time complexity than this ?
@user343882: like question like answer. You didn't mention anything about available memory, about the performance you want, about what a set actually is (a simple array, a BST (what kind of?)), about what kind of solutions you DON'T want, about whether or not you're allowed to modify the data structure used for the sets etc. You should go back and add a lot more info to your question if you want better answers.
IVlad
+4  A: 

Of course, the full-bruteforce solution described by IVlad is simple and therefore, easier and faster to write, but it's complexity is O(n3).

According to your algorithm tag, I would like to post a more complex algorithm, that has a O(n2) worst case and O(nlogn) average complexity (almost sure about this, but I'm too lazy to make a proof).

Algorithm description

Consider thinking about some abstract (X, Y, Z) tuple. We want to find a tuple that has a minimal distance between it's maximum and minimum element. What we can say at this point is that distance is actually created by our maximum element and minimum element. Therefore, the value of element between them really doesn't matter as long as it really lies between the maximum and the minimum.

So, here is the approach. We allocate some additional set (let's call it S) and combine every initial set (X, Y, Z) into one. We also need an ability to lookup the initial set of every element in the set we've just created (so, if we point to some element in S, let's say S[10] and ask "Where did this guy come from?", our application should answer something like "He comes from Y).

After that, let's sort our new set S by it's keys (this would be O(n log n) or O(n) in some certain cases)

Determining the minimal distance

Now the interesting part comes. What we want to do is to compute some artificial value, let's call it minimal distance and mark it as d[x], where x is some element from S. This value refers to the minimal max - min distance which can be achived using the elements that are predecessors / successors of current element in the sequence.

Consider the following example - this is our S set(first line shows indexes, second - values and letters X, Y and Z refer to initial sets):

0 1 2 3 4  5  6  7
------------------
1 2 4 5 8 10 11 12
Y Z Y X Y  Y  X  Z

Let's say we want to compute that our minimal distance for element with index 4. In fact, that minimal distance means the best (x, y, z) tuple that can be built using the selected element.

In our case (S[4]), we can say that our (x, y, z) pair would definitely look like (something, 8, something), because it should have the element we're counting the distance for (pretty obvious, hehe).

Now, we have to fill the gaps. We know that elements we're seeking for, should be from X and Z. And we want those elements to be the best in terms of max - min distance. There is an easy way to select them.

We make a bidirectional run (run left, the run right from current element) seeking for the first element-not-from-Y. In this case we would seek for two nearest elements from X and Z in two directions (4 elements total).

This finding method is what we need: if we select the first element of from X while running (left / right, doesn't matter), that element would suit us better than any other element that follows it in terms of distance. This happens because our S set is sorted.

In case of my example (counting the distance for element with index number 4), we would mark elements with indexes 6 and 7 as suitable from the right side and elements with indexes 1 and 3 from the left side.

Now, we have to test 4 cases that can happen - and take the case so that our distance is minimal. In our particular case we have the following (elements returned by the previous routine):

Z  X  Y   X  Z
2  5  8  11 12

We should test every (X, Y, Z) tuple that can be built using these elements, take the tuple with minimal distance and save that distance for our element. In this example, we would say that (11, 8, 12) tuple has the best distance of 4. So, we store d[5] = 4 (5 here is the element index).

Yielding the result

Now, when we know how to find the distance, let's do it for every element in our S set (this operation would take O(n2) in the worst case and better time - something like O(nlogn) in average).

After we have that distance value for every element in our set, just select the element with minimal distance and run our distance counting algorithm (which is described above) for it once again, but now save the (-, -, -) tuple. It would be the answer.

Pseudocode

Here is comes the pseudocode, I tried to make it easy to read, but it's implementation would be more complex, because you'll need to code set lookups *("determine set for element"). Also note that determine tuple and determine distance routines are basically the same, but the second yields the actual tuple.

COMBINE (X, Y, Z) -> S 
SORT(S)

FOREACH (v in S)
   DETERMINE_DISTANCE(v, S) -> d[v]

DETERMINE_TUPLE(MIN(d[v]))

P.S

I'm pretty sure that this method could be easily used for (-, -, -, ... -) tuple seeking, still resulting in good algorithmic complexity.

Kotti
+1: very well elaborated!
tangens
"We should test every (X, Y, Z) tuple that can be built using these elements" - you lost me here I'm afraid. One of these will always be `8`, right, because that's the element you're finding the distance for. So this step will be `O(N^2)`. But you are doing this step `O(N)` times, so isn't the total `O(N^3)`? Also, why is `(11, 8, 12)` the best? It looks to me like `(11, 8, 2)` is much better.
IVlad
The first step in worst case has `O(N)` complexity, because in that worst case you would have to do two passes on your `S` set (forward and backward). The lookup, that means testing 4 available possibilities (see my answer) requires `O(1)` time. You do this `O(N)` times and therefore, get `O(N2)` worst-case complexity.
Kotti
In `(11, 8, 12)` min equals `8`, max equals `12` and distance, therefore, equals `12 - 8 = 4`. In `(11, 8, 2)` distance equals `11 - 2 = 9`... Or I misunderstood the problem somewhere?
Kotti
Oops, sorry, I thought it asked for the maximum difference for a second there :). You're right about that part, but I still don't get why this is `O(N^2)`. For each element (`O(N)`), you find the tuple that you can best build around this element. For this, you scan the entire superset (S1 + S2 + S3) to find out what elements you can select. This is already `O(N^2)`. Then, for those that you can select, you find the best pair that minimizes the distance. Why are there only 4 cases? I would think there are `O(N^2)` cases in general, resulting in `O(N^3)` total.
IVlad
I think you didn't get the important part of my approach (probably, I should explain it better). The important part here is sorting. In your algorithm you would have to make element-by-element comparisons for each of them and that would result in `O(N2) * O(N)` complexity. In my variation when you meet an element that suits you, you already know that every element after it would suit you worse than the first one. Take a look at the sample: `5(Y) - > 6(X) -> 7(X)`, we're traversing right. So, if we say that `6(X)` here suits us, we can also say that `7(X)` wouldn't suit us, because `6(X)`
Kotti
suits better (our element sequence is sorted, therefore any `X` element after `6(X)` would result in bigger distance, than `6(X)`)...
Kotti
I see, that makes sense now :).
IVlad
@IVlad: Think of it this way: You sort each set separately. Now for each x, you find where it lies in the set for y and set for z. Now how many cases do you need to look at to determine the best triplet containing that x? All this merging and tagging and looking around was just fluff and confuses the main issue.
Moron