题目地址:
https://www.lintcode.com/problem/merge-k-sorted-interval-lists/description
给定一个若干个闭区间组成的列表的列表,每个内层列表已经按照区间的左端点由小到大排好序了。要求将所有的区间做合并,然后按照从左到右的顺序输出。
法1:分治法。类似归并排序的方法,先递归合并排序左半边数量的列表,再递归合并排序右半边数量的列表,最后合并两个列表。代码如下:
import java.util.ArrayList;
import java.util.List;
public class Solution {
/**
* @param intervals: the given k sorted interval lists
* @return: the new sorted interval list
*/
public List<Interval> mergeKSortedIntervalLists(List<List<Interval>> intervals) {
// write your code here
return mergeSort(intervals, 0, intervals.size() - 1);
}
private List<Interval> mergeSort(List<List<Interval>> intervals, int l, int r) {
if (l > r) {
return new ArrayList<>();
}
if (l == r) {
return intervals.get(l);
}
// 合并排序两半边
int mid = l + (r - l >> 1);
List<Interval> left = mergeSort(intervals, l, mid), right = mergeSort(intervals, mid + 1, r);
List<Interval> res = new ArrayList<>();
for (int i = 0, j = 0; i < left.size() || j < right.size(); ) {
if (i == left.size()) {
extend(res, right.get(j++));
} else if (j == right.size()) {
extend(res, left.get(i++));
} else {
Interval i1 = left.get(i), i2 = right.get(j);
if (i1.start <= i2.start) {
extend(res, i1);
i++;
} else {
extend(res, i2);
j++;
}
}
}
return res;
}
// extend的功能是,将interval这个区间“融入”进list里
private void extend(List<Interval> list, Interval interval) {
// 如果list没有元素,就直接将interval加进去
if (list.isEmpty()) {
list.add(interval);
return;
}
Interval last = list.get(list.size() - 1);
// 如果没有交集,则直接加;否则拓展最后一个区间的右端点
if (interval.start > last.end) {
list.add(interval);
} else {
last.end = Math.max(last.end, interval.end);
}
}
}
class Interval {
int start, end;
public Interval(int start, int end) {
this.start = start;
this.end = end;
}
}
时间复杂度 O ( n l log n ) O(nl\log n) O(nllogn),空间 O ( n l ) O(nl) O(nl), n n n是list的数量, l l l是最长list的长度,空间 O ( n ) O(n) O(n)。
法2:最小堆。把每个interval包装成一个Pair类,记录其在原lists里的坐标(可以将lists看成一个二维矩阵),然后开一个最小堆,按照左端点排序。接着将每个list的第一个interval加入堆中,接着每次poll一个出来就加入答案,然后将这个interval在二维矩阵中的右边的interval入堆。如此直到堆空。代码如下:
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
public class Solution {
class Pair {
int x, y;
Interval interval;
public Pair(int x, int y, Interval interval) {
this.x = x;
this.y = y;
this.interval = interval;
}
}
/**
* @param intervals: the given k sorted interval lists
* @return: the new sorted interval list
*/
public List<Interval> mergeKSortedIntervalLists(List<List<Interval>> intervals) {
// write your code here
PriorityQueue<Pair> minHeap = new PriorityQueue<>((i1, i2) -> Integer.compare(i1.interval.start, i2.interval.start));
for (int i = 0; i < intervals.size(); i++) {
// 注意要判空
if (!intervals.get(i).isEmpty()) {
minHeap.offer(new Pair(i, 0, intervals.get(i).get(0)));
}
}
List<Interval> res = new ArrayList<>();
while (!minHeap.isEmpty()) {
Pair cur = minHeap.poll();
extend(res, cur.interval);
// 如果有下一个,就将下一个入堆
if (cur.y + 1 < intervals.get(cur.x).size()) {
minHeap.offer(new Pair(cur.x, cur.y + 1, intervals.get(cur.x).get(cur.y + 1)));
}
}
return res;
}
private void extend(List<Interval> list, Interval interval) {
if (list.isEmpty()) {
list.add(interval);
return;
}
Interval last = list.get(list.size() - 1);
if (interval.start > last.end) {
list.add(interval);
} else {
last.end = Math.max(last.end, interval.end);
}
}
}
时间复杂度 O ( n l log n ) O(nl\log n) O(nllogn), n n n是list的数量, l l l是最长list的长度,空间 O ( n ) O(n) O(n)。