小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
题目描述
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。
思路1-标记
-
使用count记录区间的长度.
-
计算公式: count = 1 + end - start;
-
将区间[start, end] 得出的count放入标记数组flag中,start是索引,count是值, 如果有重复的start,放入更大的count。
-
遍历标记数组,获取区间,设置一个右边界指针,遍历时检测是否出现更大的边界值,有则替换。
-
思路清晰,速度超快
-
时间复杂度:O(n + m) n 原数组长度, m 标记数组长度(总区间内最大值加一)
-
空间复杂度:O(m)
class Solution {
public int[][] merge(int[][] intervals) {
int max = -1; //生成标记数组的最大索引
for (int[] interval : intervals) {
if (max < interval[1]) {
max = interval[1];
}
}
int[] flag = new int[++max]; //标记数组
int start, end, count;
for (int[] interval : intervals) {
start = interval[0];
end = interval[1];
count = 1 + end - start;
if (flag[start] == 0) {
flag[start] = count;
} else if (flag[start] < count) {
flag[start] = count;
}
}
//遍历flag,获取区间
int index = 0, pos = 0, right;
while (index < max) {
if (flag[index] > 0) {
start = index;
right = start + flag[index]; //右边界 不包含
for (int i = start + 1; i < right; i++) {
if (flag[i] != 0 && i + flag[i] > right) { //替换右边界
right = i + flag[i];
}
}
intervals[pos][0] = start;
intervals[pos][1] = right - 1;
pos++;
index = right;
} else {
index++;
}
}
int[][] res = new int[pos][2];
System.arraycopy(intervals, 0, res, 0, pos);
return res;
}
}
思路2-双队列
class Solution {
public int[][] merge(int[][] intervals) {
if(intervals.length==0){
return intervals;
}
Arrays.sort(intervals,(i, j) -> Integer.compare(i[0],j[0]));
List<int[]> inQueue = new LinkedList<>();
Collections.addAll(inQueue,intervals);
List<int[]> outQueue = new LinkedList<>();
while (inQueue.size()>1){
int[] i = inQueue.remove(0);
int[] j = inQueue.remove(0);
if(i[0]==j[0]){
if(i[1]>=j[1]){
inQueue.add(0,i);
}else{
inQueue.add(0,j);
}
}else{
if(i[1]<j[0]){
outQueue.add(i);
inQueue.add(0,j);
}else{
if(i[1]>=j[1]){
inQueue.add(0,i);
}else{
inQueue.add(0,new int[]{i[0],j[1]});
}
}
}
}
outQueue.add(inQueue.get(0));
return outQueue.toArray(new int[][]{});
}
}