/**
* Definition for an interval.
* public class Interval {
* int start;
* int end;
* Interval() { start = 0; end = 0; }
* Interval(int s, int e) { start = s; end = e; }
* }
*/
public class Solution {
public List<Interval> merge(List<Interval> intervals) {
Deque<Interval> stack = new ArrayDeque<Interval>();
Collections.sort(intervals, new Comparator<Interval>() {
public int compare(Interval p1, Interval p2) {
return Integer.compare(p1.start, p2.start);
}
}
);
if (intervals.size() < 1) {
return intervals;
}
stack.push(intervals.get(0));
for (int j = 1; j < intervals.size(); j++) {
Interval i = intervals.get(j);
Interval top = stack.peek();
if (top.end < i. start) {
stack.push(i);
}
else if (top.end < i.end) {
top.end = i.end;
}
}
return new ArrayList<Interval>(stack);
}
}
按起始点对片段进行排序。
然后,对于每个片段,如果它的起始点在前一个片段的起始点和结束点之间,并且它的结束点大于前一个片段的结束点,则将前一个片段的结束点设置为该片段的结束点,并删除/忽略当前片段。
如果当前片段完全包含在前一个片段中,则只需删除/忽略它。
由于排序,这是 O(n log n)
的算法,你不需要将每个片段与所有其他片段进行比较。
要注意如何进行删除或忽略。这应该是一个 O(1)
的操作。例如,保持一个变量,始终存储前一个未被删除的片段,并可能使用一些标记来标记已删除的片段,以便在最后可以收集到哪些片段被删除了。.remove()
操作可能是 O(n)
的,你需要避免这种情况。
+
然后是-
)。然后对列表进行排序。0+ 0.75- 0.5+ 1- 1.25+ 2-
接着,排序完成,
0+ 0.5+ 0.75- 1- 1.25+ 2-
给出计数(初始化为0
)
1 2 1 0 1 0
0到>0
或>0到0
)。0 1 1.25 2
这也可以在原地、无需额外标志的情况下完成。
您可以将start
和end
值分别就地排序(不要整体移动Segments
),这样极性就保持不变了。
然后遍历列表,将其视为两个已排序列表的合并(使用两个独立索引),并维护重叠计数器。您可以原地覆盖边界,因为合并的结果没有更多间隔。
从以下内容开始:
[0 0.75][0.5 1][1.25 2]
这两个列表已经意外地被排序了。
0 0.5 1.25 (+)
0.75 1 2 (-)
继续合并,将按顺序选择元素。
+ + - - + -
[0 1][1.25 2][x x]
如果边界存在并列的情况,最好按照一定顺序处理+
和-
,以避免发出两个相等的边界。