This is solvable in O(max(M,N) log(max(M,N)))
(the time to sort letters and envelopes) with a 2D vertical-sweep-line algorithm. This is the same as O(M+N log (M+N))
.
Since rotation is allowed, swap any pair (x, y)
of letter/envelope dimensions so that x <= y
.
Combine the lists, marking the original list of each point. We can do this by making (x, y, 'E')
represent points from the Envelope list, for example, and 'L' for letters.
Sort the list by x
, then by y
to tiebreak, then with 'L' before 'E' if still tied. We're going to treat a letter (x0, y0, 'L')
as a point in 2D space, which can match any 'envelope' point (x1, y1, 'E')
if and only if x0 <= y0 and x1 <= y1
.
Initialize a balanced binary-search-tree (BST) unmatched_letters
, which will contain our so-far-unmatched letters, with their key/ordering in the BST based on their y-value only.
The idea is that we'll be moving a vertical sweep line over the points, from left to right, processing the points on the line from bottom to top (this is the exact order our list is already sorted in):
- If we see a letter, we'll add it to our
unmatched_letters
BST, sorted by 'y'. That means any envelopes we see after adding it only need to be checked for larger/equal 'y' values (the sweep line ensures the later x value isn't smaller).
- If we see an envelope, we'll try to match it with the highest-height letter available for it in our BST using a binary search. If there is none, we can 'throw away'/disregard that envelope, since any letters we see in the future will either have higher x or y values than this envelope. Otherwise, match them. You can show by a greedy-exchange argument that this will give the optimal solution; I may include a proof of that if it isn't too long or nontrivial.
For the more detailed, 'pseudocode' version of the step we just described:
- Iterate over the
(x0, y0, category)
points in our list. If category == 'L'
, insert it to unmatched_letters
with key y0
. If category == 'E'
, binary-search for the largest key-value in unmatched_letters
that is at most y0
. If there is a match: the letter has an x-value at most x0
since it was processed earlier. Remove that letter, and record it as part of our solution with this envelope.
Since all we did was sort the lists and iterate, this can clearly be done in O(sorting)
. It's not hard to argue why this must give a maximum matching, but the exact proof of greedy algorithms' correctness can be long. Part of the argument goes like this: if we compare to any fixed, optimal solution, and the earliest difference (by x-coordinate) is that greedy matches envelope 'E1' with letter 'L1' and optimal doesn't, then there are two (not disjoint) possibilities:
- In the optimal solution, 'E1' matches a different letter, 'L2'. By construction, 'L2' has a y-value at most as large as 'L1', so if 'L1' is matched by a later (by x-value) envelope in the optimal solution, this later envelope must also fit 'L2' (and if not, we can swap 'L1' and 'L2' in optimal to match greedy).
- In the optimal solution, 'L1' matches a different envelope, 'E2'. Then, again, envelope 'E1' in the optimal solution is matched with a smaller-or-equal-y-value letter (or empty), and we can exchange these pairings in the optimal solution to match greedy.
50 1, 40 2
and envelopes55 2, 54 1
. You can find a similar example for all sorts of greedy approach. – RheeJan 4
: Either 2013 Christmas cards in which case you need O(-12day) or for 2014 you are quite early and O(Dec24,2014) will work. *<|:o)> – Lordly