【Lintcode】577. Merge K Sorted Interval Lists

题目地址:

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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值