2014-05-06 10:18
原题:
Given a set of intervals, find the interval which has the maximum number of intersections (not the length of a particular intersection). So if input (1,6) (2,3) (4,11), (1,6) should be returned. Some suggest to use Interval Tree to get this done in O(logn), but I did not understand how to construct and use the Interval Tree after reading its wiki page. Is there any other way to do it? If Interval tree is the only option, please educate me how to construct/use one. Thanks.
题目:有一堆一维的区间,请判断其中和其他区间相交次数最多的区间是哪一个。比如例子(1, 6)、(2, 3)、(4, 11),(1, 6)和其他两个相交了,所以是相交最多的。另外,这位叫“Guy”的老兄又在秀自己的无知了。说自己的第一想法是用线段树来解题,然后又说自己看了Wiki以后不知道怎么写线段树(既然压根儿不会你提它干嘛)。
解法:我的第一想法是可以用线段树,不过我不会写线段树,所以我试着用树状数组来解决问题。没想到,还真琢磨出一个来。一种暴力的解法自然是两层循环遍历,统计谁的相交次数最多。如果想把复杂度降低到O(n * log(n)),就得使元素有序。首先要明白一点:当A区间和B区间相交时,A和B的相交次数都要加1。那么,当A和BCD都相交时,A的相交次数直接加3,B、C、D的相交次数都加1。如果直接就这么加,复杂度肯定是平方级别的。但你既然看到“都加1”这种字眼,应该会联想到树状数组。树状数组的一种适用模型,就是给区间加上同一个值,然后查询单个元素,符合这道题的需求。我的代码里实现了一个简单的树状数组类,可以批量修改元素,和查询单个元素。单个操作的时间都是O(log(n))。这样n个区间统计完了以后,可以做到O(n * log(n))。在做相交统计之前,需要保证元素有序,比如按"先X后Y"或者“先Y后X”的顺序给区间排序,这个过程也是O(n * log(n))的。总体时间复杂度为O(n * log(n))。从这题可以看出:出题人不靠谱,下面回帖的答题者也大多不靠谱,有光说思路不写代码的,有分析完全错误的,还有断言时间复杂度不可能低于O(n^2)的。总之,这一题让我对Careercup上的题目质量大失所望。如果像“Guy”这样水平的用户活跃在Careercup上,这网站就完蛋了。如果需要了解树状数组,可以自行百度“树状数组”或者Google“Binary Indexed Tree”。
代码:
1 // http://www.careercup.com/question?id=6332750214725632 2 #include <algorithm> 3 #include <iostream> 4 #include <vector> 5 using namespace std; 6 7 class BinaryIndexedTree { 8 public: 9 BinaryIndexedTree(int _n = 1): n(_n) { 10 v.resize(n + 1); 11 }; 12 13 // add val to all elements from v[1] to v[x] 14 void addAll(int x, int val) { 15 while (x >= 1) { 16 v[x] += val; 17 x -= lowBit(x); 18 } 19 }; 20 21 // add val to all elements from v[x] to v[y] 22 void addInterval(int x, int y, int val) { 23 if (x > y) { 24 addInterval(y, x, val); 25 return; 26 } 27 addAll(x - 1, -val); 28 addAll(y, val); 29 }; 30 31 // return v[x] 32 int sum(int x) { 33 int res = 0; 34 while (x <= n) { 35 res += v[x]; 36 x += lowBit(x); 37 } 38 39 return res; 40 }; 41 42 ~BinaryIndexedTree() { 43 v.clear(); 44 }; 45 private: 46 int n; 47 vector<int> v; 48 49 int lowBit(int x) { 50 return x & -x; 51 }; 52 }; 53 54 struct Interval { 55 int start; 56 int end; 57 Interval(int _start = 0, int _end = 0): start(_start), end(_end) {}; 58 59 bool operator < (const Interval &other) { 60 if (start != other.start) { 61 return start < other.start; 62 } else { 63 return end < other.end; 64 } 65 }; 66 67 friend ostream& operator << (ostream &cout, const Interval &i) { 68 cout << '(' << i.start << ',' << i.end << ')'; 69 return cout; 70 }; 71 }; 72 73 Interval solve(vector<Interval> &v) 74 { 75 int n = (int)v.size(); 76 77 if (n == 0) { 78 return Interval(0, 0); 79 } else if (n == 1) { 80 return v[0]; 81 } 82 83 sort(v.begin(), v.end()); 84 BinaryIndexedTree bit(n); 85 86 int i, j; 87 int ll, rr, mm; 88 for (i = 0; i < n - 1; ++i) { 89 if (v[i + 1].start >= v[i].end) { 90 // no overlapping 91 continue; 92 } 93 94 if (v[n - 1].start < v[i].end) { 95 // all overlapped 96 j = n - 1; 97 } else { 98 ll = i + 1; 99 rr = n - 1; 100 while (rr - ll > 1) { 101 mm = (ll + rr) / 2; 102 if (v[mm].start < v[i].end) { 103 ll = mm; 104 } else { 105 rr = mm; 106 } 107 } 108 j = ll; 109 } 110 // from [i + 1, j], they all overlap with v[i]. 111 bit.addInterval(i + 2, j + 1, 1); 112 bit.addInterval(i + 1, i + 1, j - i); 113 } 114 115 int ri; 116 int res, mres; 117 118 ri = 0; 119 mres = bit.sum(1); 120 for (i = 1; i < n; ++i) { 121 res = bit.sum(i + 1); 122 ri = res > mres ? i : ri; 123 } 124 125 return v[ri]; 126 } 127 128 int main() 129 { 130 int i; 131 int n; 132 vector<Interval> v; 133 Interval res; 134 135 while (cin >> n && n > 0) { 136 v.resize(n); 137 for (i = 0; i < n; ++i) { 138 cin >> v[i].start >> v[i].end; 139 } 140 res = solve(v); 141 cout << res << endl; 142 v.clear(); 143 } 144 145 return 0; 146 } 147 148 /* 149 // A simple test for the BIT above. 150 int main() 151 { 152 string cmd; 153 int n; 154 BinaryIndexedTree *bit = nullptr; 155 int x, y, val; 156 int i; 157 158 while (cin >> n && n > 0) { 159 bit = new BinaryIndexedTree(n); 160 while (true) { 161 for (i = 1; i <= n; ++i) { 162 cout << bit->sum(i) << ' '; 163 } 164 cout << endl; 165 cin >> cmd; 166 if (cmd == "e") { 167 break; 168 } else if (cmd == "a") { 169 cin >> x >> val; 170 bit->addAll(x, val); 171 } else if (cmd == "ai") { 172 cin >> x >> y >> val; 173 bit->addInterval(x, y, val); 174 } 175 } 176 delete bit; 177 bit = nullptr; 178 } 179 180 return 0; 181 } 182 */