Describe an algorithm that takes an unsorted array of axis‐aligned rectangles and returns any pair of rectangles that overlaps, if there is such a pair. Axis‐aligned means that all the rectangle sides are either parallel or perpendicular to the x‐ and y‐axis. You can assume that each rectangle object has two variables in it: the x‐y coordinates of the upper‐left corner and the bottom‐right corner.
Good Answer: Create a sorted array of the x coordinates of the left and right edges of the rectangles. Then, use a "scanline" to move from left to right through the rectangles. Keep a binary search tree containing the y coordinates of the top and bottom edges of the rectangles that overlap the scanline. For each element of the array, check whether it is a left or right edge. If it is a right edge, remove the corresponding top and bottom edges from the BST. If it is a left edge, search the BST for rectangles that overlap the current rectangle; if there is one, return the overlap. Then, add the y coordinates of the top and bottom edges of the rectangle to the BST. The search takes O(n log n) time, since it takes O(n log n) time to sort the rectangles and each of the 2n iteration s takes O(log n) time.
C++ Sample Code (Find all pairs of rectangles that overlap):
1 #include <iostream> 2 #include <vector> 3 #include <map> 4 #include <algorithm> 5 using namespace std; 6 7 struct rect { 8 int _x1, _x2, _y1, _y2; 9 rect(int x1, int x2, int y1, int y2) : 10 _x1(x1), _x2(x2), _y1(y1), _y2(y2) {} 11 }; 12 13 struct xedge { 14 int _x; 15 int _is_left; 16 int _i_rect; 17 xedge(int x, int is_left, int i_rect) : 18 _x(x), _is_left(is_left), _i_rect(i_rect) {} 19 }; 20 21 struct yedge { 22 int _y; 23 int _is_top; 24 int _i_rect; 25 yedge(int y, int is_top, int i_rect) : 26 _y(y), _is_top(is_top), _i_rect(i_rect) {} 27 }; 28 29 int main() { 30 vector<rect> rcts; // vector that stores rectangles 31 vector<xedge> xes; // left and right edges of the rectangles 32 int x1, x2, y1, y2; 33 int i = 0; 34 while (cin >> x1 >> x2 >> y1 >> y2) { 35 rcts.push_back(rect(x1, x2, y1, y2)); 36 xes.push_back(xedge(x1, 1, i)); 37 xes.push_back(xedge(x2, 0, i)); 38 i++; 39 } 40 41 // sort left and right rectangles according to their x-coordinates 42 sort(xes.begin(), xes.end(), 43 [](const xedge& e1, const xedge& e2) { 44 if (e1._x != e2._x) return e1._x < e2._x; 45 else if (e1._is_left != e2._is_left) 46 return e1._is_left > e2._is_left; 47 else return e1._i_rect < e2._i_rect; 48 }); 49 50 // a binary search tree for top and bottom edges that overlap the "scanline" 51 multimap<int, yedge> edge_map; 52 for (auto& xe : xes) { // xe : "scanline" 53 if (!xe._is_left) { 54 auto range = edge_map.equal_range(rcts[xe._i_rect]._y1); 55 for (auto iter = range.first; iter != range.second; ++iter) { 56 if (iter->second._i_rect == xe._i_rect) { 57 edge_map.erase(iter); 58 break; 59 } 60 } 61 range = edge_map.equal_range(rcts[xe._i_rect]._y2); 62 for (auto iter = range.first; iter != range.second; ++iter) { 63 if (iter->second._i_rect == xe._i_rect) { 64 edge_map.erase(iter); 65 break; 66 } 67 } 68 } else { 69 int y1 = rcts[xe._i_rect]._y1; 70 int y2 = rcts[xe._i_rect]._y2; 71 auto iter1 = edge_map.lower_bound(y1); 72 auto iter2 = edge_map.upper_bound(y2); 73 for (auto iter = iter1; iter != iter2; ++iter) { 74 cout << xe._i_rect << " " << iter->second._i_rect << endl; 75 } 76 edge_map.insert(make_pair(y1, yedge(y1, 0, xe._i_rect))); 77 edge_map.insert(make_pair(y2, yedge(y2, 1, xe._i_rect))); 78 } 79 } 80 81 return 0; 82 }