leetcode - Insert Interval
来源:互联网 发布:淘宝一千多的硅胶娃娃 编辑:程序博客网 时间:2024/04/29 17:41
Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).
You may assume that the intervals were initially sorted according to their start times.
Example 1:
Given intervals [1,3],[6,9]
, insert and merge [2,5]
in as [1,5],[6,9]
.
Example 2:
Given [1,2],[3,5],[6,7],[8,10],[12,16]
, insert and merge [4,9]
in as [1,2],[3,10],[12,16]
.
This is because the new interval [4,9]
overlaps with [3,5],[6,7],[8,10]
.
/** * Definition for an interval. * struct Interval { * int start; * int end; * Interval() : start(0), end(0) {} * Interval(int s, int e) : start(s), end(e) {} * }; */class Solution {public:#define M2 #ifdef M1// O(n2) time, O(1) space, TLE超时 vector<Interval> insert(vector<Interval> &intervals, Interval newInterval) { vector<Interval>::iterator iter = intervals.begin(); while(iter != intervals.end()) { if (newInterval.end < iter->start) { intervals.insert(iter, newInterval); return intervals; } else if (iter->end < newInterval.start) { ++iter; } else { newInterval.start = min(newInterval.start, iter->start); newInterval.end = max(newInterval.end, iter->end); iter = intervals.erase(iter); // erase will return iterator of next item before iter is removed. } } intervals.insert(intervals.end(), newInterval); return intervals; }#endif#ifdef M2/*利用intervals已经排序的特点,采用二分查找,可以在O(lgn)时间内找到起点和终点。这里的最坏情况还是O(n),即要insert的Interval跨头和尾的位置。binarySearch:// 二分查找的变形,将intervals中所有的元素展开(也就是说不分start,end),可以看成一个排序数组。// low,mid,high和经典二分查找类似;// mid为在展开的数组中的下标,而idx为该元素在intervals数组的下标;// mid对应的是intervals[idx]的start还是end呢? 如果mid-2*idx == 1, 则是end,==0,则是start。// 这个函数有点类似于lower_bound, 它的返回值也可以参考lower_bound来理解。[ [1,2] ], 0: 返回0[ [1,5] ], 3: 返回0[ [3,6] ], 7: 返回1[ [1,2] [5,8] ], 0/1/2: 返回0[ [1,2] [5,8] ], 3/4/5/6/7/8: 返回1[ [1,2] [5,8] ], 9: 返回2*/ int binarySearch(vector<Interval> &intervals, int val) { int low = 0, high = intervals.size()*2-1; while(low <= high) { int mid = (low+high)/2; // index in all numbers int idx = mid/2; // index in intervals array int midv; Interval midItem= intervals[idx]; //mid -2*idx == 1 or 0 midv = (mid-2*idx) ? midItem.end : midItem.start; if (midv == val) { return idx; } else if (midv < val) { low = mid+1; } else { high = mid-1; } } return low/2; } vector<Interval> insert(vector<Interval> &intervals, Interval newInterval) { int pos1 = binarySearch(intervals, newInterval.start); int pos2 = binarySearch(intervals, newInterval.end); // newInterval.start is bigger than all numbers in intervals or intervals is empty // [], [1,2] => [ [1,2] ] // [ [1,2] ], [3, 4] => [ [1,2] [3,4] ] if (pos1 == intervals.size()) { intervals.push_back(newInterval); return intervals; } // if newInterval.end is bigger than all numbers in interval, then it will merge with last item. // [ [1,3] ], [2, 5] => [ [1,5] ] if (pos2 == intervals.size()) { pos2 = intervals.size()-1; } // 对于newInterval.start,有两种情况: // newInterval.start < intervals[pos1].start // newInterval.start >= intervals[pos1].start // 不管哪种情况,都需要将newInterval和intervals[pos1]合并。 newInterval.start = min(newInterval.start, intervals[pos1].start); // 对于newInterval.end, 同样有两情况: // newInterval.end < intervals[pos2].start // newInterval.end >= intervals[pos2].start // 对于第一种情况,我们需要将newInterval和intervals[pos2-1]合并。此时注意要保证pos2-1>=0 // 对于第二种情况,我们将newInterval和intervals[pos2]合并即; if (newInterval.end < intervals[pos2].start) { if (pos2-1 >= 0) { newInterval.end = max(newInterval.end, intervals[pos2-1].end); } pos2--; } else { newInterval.end = max(newInterval.end, intervals[pos2].end); } // [ [3,5] ], [1,2] => [ [1,2] [3,5] ], pos1=0, pos2=0-1=-1 // [ [3,5] [8,9] ], [6,7] => [ [3,5] [6,7] [8,9] ], pos1=1, pos2=1-1=0 if (pos1 > pos2) { intervals.insert(next(intervals.begin(), pos1), newInterval); } else { // [ [2,5] ], [3,4] => [ [2,5] ], pos1=0, pos2=0 // [ [1,4] [6,8] ], [2,5] => [ [1,5] [6,8] ], pos1=0, pos2=1-1=0 // [ [1,4] [6,8] ], [2,7] => [ [1,8] ], pos1=0, pos2=1 typedef vector<Interval>::iterator Iterator; Iterator iter1 = next(intervals.begin(), pos1); Iterator iter2 = next(intervals.begin(), pos2+1); //[first, last), 所以pos2+1,不然pos2那个位置不会被erase。 iter1 = intervals.erase(iter1, iter2); // 返回iter2之后的位置,这里返回的iter1已经不等于iter2了,因为iter2已经失效了。 intervals.insert(iter1, newInterval); } return intervals; }#endif};class Solution {public:/*如果用网上的代码,最好的情况是直接插入,不用合并,O(n),最坏的情况是待插入的Interval横跨所有的Intervals,O(n2),因为erase时需要拷贝数组元素,所以会超时。原来自己也写过一个用二分查找的方法,但现在觉得那个代码要判断的条件太多了。这种代码自己平时有时间是可以写出来的,但是需要一些调试才能保证正确性。于是再次思考,觉得应该有更好的写法,因此有了以下代码。这个代码思路清晰,简洁,不容易出错,给别人解释也比较容易。空间复杂度: 这种实现需要O(n)的空间。时间复杂度:构造vector<int>, O(n)binary search: O(logn);insert: 最坏是在头部插入O(n),最好是在尾部插入,O(1),平均是O(n);distance: O(1), 注意insert时如果用list插入效率高,但是distance就得O(n)了;构造vector<Interval> O(n)所以最坏情况也是O(n)的时间复杂度。原理:1. 先用一个int数组保存Interval中的数,由于已经排序,所以可以用binary search。 理解STL中的lower_bound很重要,经典代码不多说。2. 找到合适的插入位置之后,分别插入newInterval的start和end,得到他们插入之后的位置。3. 第一个位置应该在某个Interval的左边,第二个位置则需要在某个Interval的右边,如果不是则需要调整这两个位置。 在处理第二个位置时,对于相同元素要进一步处理: Input: [[1,5]], [0,1] Output: [[0,1],[1,5]] Expected: [[0,5]]4. 这两个位置之间的元素都需要去掉,其它的元素保留, 所以只需将有效元素重新填到Interval数组中去即可。*/ // lower_bound 返回大于等于val的第一个位置 template <typename FI, typename T> FI lower_bound(FI first, FI last, const T &val) { while(first < last) { FI mid = next(first, distance(first, last)/2); if (*mid < val) first = next(mid); else last = mid; } return first; } vector<Interval> insert(vector<Interval> &intervals, Interval newInterval) { vector<int> v2; for(auto i:intervals) { v2.push_back(i.start); v2.push_back(i.end); } auto pos1 = lower_bound(v2.begin(), v2.end(), newInterval.start); pos1 = v2.insert(pos1, newInterval.start); // 插入后返回所插入元素的实际位置 int idx1 = distance(v2.begin(), pos1); // !!! 这里必须先算出idx1,不然在下面插入newInterval.end后pos1可能会失效。 // pos2肯定大于pos1,因为newInterval.end >= newInterval.start auto pos2 = lower_bound(v2.begin(), v2.end(), newInterval.end); pos2 = v2.insert(pos2, newInterval.end); int idx2 = distance(v2.begin(), pos2); if (idx1%2 == 1) idx1--; // 保证是一个Interval的start if (idx2%2 == 0) idx2++; // 保证是一个Interval的end // 进一步合并相同的元素,如[[1,5],插入[0,1]后,[0, 1][1,5] => [0,5] if (idx2+1 < v2.size() && v2[idx2] == v2[idx2+1]) idx2+=2; // 将有效元素填入Interval数组中。 vector<Interval> result; for(int i=0; i<idx1; i+=2) result.push_back({v2[i], v2[i+1]}); result.push_back({v2[idx1], v2[idx2]}); for(int i=idx2+1; i<v2.size(); i+=2) result.push_back({v2[i], v2[i+1]}); return result; }};
0 0
- LeetCode: Insert Interval & Merge Interval
- LeetCode题目 Insert Interval
- LeetCode: Insert Interval
- LeetCode Insert Interval
- LeetCode: Insert Interval
- Leetcode: Insert Interval
- [LeetCode] Insert Interval
- LeetCode Insert Interval
- [LeetCode]Insert Interval
- leetcode insert interval
- [leetcode]Insert Interval
- LeetCode-Insert Interval
- [leetcode] Insert Interval
- LeetCode - Insert Interval
- 【leetcode】Insert Interval
- leetcode Insert Interval
- 【leetcode】Insert Interval
- LeetCode Insert Interval
- virtual虚函数
- jquery $("#id").click()
- 华为实习生笔试练习4.9
- 声音特征提取:MFCC向量
- kafka的生产者和消费者的理解
- leetcode - Insert Interval
- https原理
- 使用JS对form的内容验证失败后阻止提交
- Unity3d linux版本如果做Splash屏幕
- 汽车加油
- STL 源码分析 # stl_number #
- java集合框架List之ArrayList(二)
- Collection与Map
- Android侧滑菜单DrawerLayout