Interval 间隔问题

2018-09-07 09:03:14

一、Merge Intervals

问题描述:

问题求解:

    public List<Interval> merge(List<Interval> intervals) {
        List<Interval> res = new ArrayList<>();
        if (intervals.size() == 0) return res;
        Collections.sort(intervals, new Comparator<Interval>() {
            public int compare(Interval o1, Interval o2) {
                return o1.start - o2.start;
            }
        });
        int start = intervals.get(0).start;
        int end = intervals.get(0).end;
        for (int i = 1; i < intervals.size(); i++) {
            if (intervals.get(i).start > end) {
                res.add(new Interval(start, end));
                start = intervals.get(i).start;
                end = intervals.get(i).end;
            }
            else {
                end = Math.max(end, intervals.get(i).end);
            }
        }
        res.add(new Interval(start, end));
        return res;
    }

 

二、Insert Interval

问题描述:

问题求解:

本题的问题描述中明确的说明了,本题的给出条件中的intervals是已经排序好的,并且是没有overlapping的,因此在后续的求解过程中只需要一次遍历即可。

    public List<Interval> insert(List<Interval> intervals, Interval newInterval) {
        List<Interval> res = new ArrayList<>();
        int i = 0;
        while (i < intervals.size() && intervals.get(i).end < newInterval.start) {
            res.add(intervals.get(i++));
        }
        while (i < intervals.size() && intervals.get(i).start <= newInterval.end) {
            newInterval.start = Math.min(newInterval.start, intervals.get(i).start);
            newInterval.end = Math.max(newInterval.end, intervals.get(i).end);
            i++;
        }
        res.add(newInterval);
        while (i < intervals.size()) res.add(intervals.get(i++));
        return res;
    }

 

三、My Calendar I

问题描述:

问题求解:

解法一:Boundary Counting

对边界进行计数,最后遍历一遍即可,如果过程中有curSum大于1的情况,则表明出现了overlapping。

如果使用keySet()则会多出log(n)的时间,而本题卡时间非常紧,如果使用key进行提取,则会TLE。

如果使用entrySet(),则会Accept,但是也是将将通过。

public class MyCalendar {   
  TreeMap<Integer, Integer> map;

    public MyCalendar() {
        map = new TreeMap<>();
    }
    
    public boolean book(int start, int end) {
        return helper(start, end);
    }
    
    private boolean helper(int start, int end) {
        map.put(start, map.getOrDefault(start, 0) + 1);
        map.put(end, map.getOrDefault(end, 0) - 1);
        int curSum = 0;
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            curSum += entry.getValue();
            if (curSum > 1) {
                map.put(start, map.get(start) - 1);
                if (map.get(start) == 0) map.remove(start);
                map.put(end, map.get(end) + 1);
                if (map.get(end) == 0) map.remove(end);
                return false;
            }
        }
        return true;
    }
}

解法二、

记录各个interval,并且所有的interval都是没有overlapping的。

public class MyCalendar {      
  TreeMap<Integer, Integer> treeMap; public MyCalendar() { treeMap = new TreeMap<>(); } public boolean book(int start, int end) { Integer floor = treeMap.floorKey(start); if (floor != null && treeMap.get(floor) > start) return false; Integer ceil = treeMap.ceilingKey(start); if (ceil != null && ceil < end) return false; treeMap.put(start, end); return true; }
}

 

四、My Calendar II

问题描述:

问题求解:

万能的Boundary Counting。

public class MyCalendarTwo {
    TreeMap<Integer, Integer> map;

    public MyCalendarTwo() {
        map = new TreeMap<>();
    }

    public boolean book(int start, int end) {
        map.put(start, map.getOrDefault(start, 0) + 1);
        map.put(end, map.getOrDefault(end, 0) - 1);
        int cnt = 0;
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            cnt += entry.getValue();
            if (cnt > 2) {
                map.put(start, map.get(start) - 1);
                if (map.get(start) == 0) map.remove(start);
                map.put(end, map.get(end) + 1);
                if (map.get(end) == 0) map.remove(end);
                return false;
            }
        }
        return true;
    }
}

 

五、My Calendar III

问题描述:

问题求解:

解法一:

万能的Boundary Counting。

public class MyCalendarThree {
    TreeMap<Integer, Integer> map;

    public MyCalendarThree() {
        map = new TreeMap<>();
    }

    public int book(int start, int end) {
        map.put(start, map.getOrDefault(start, 0) + 1);
        map.put(end, map.getOrDefault(end, 0) - 1);
        int res = 0;
        int cnt = 0;
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            cnt += entry.getValue();
            if (res < cnt) res = cnt;
        }
        return res;
    }
}

解法二:

线段树求解,效率有较大的提升。

public class MyCalendarThree {
    SegmentTree root;
    int res;

    public MyCalendarThree() {
        root = new SegmentTree(0, 1000000000, 0);
        res = 0;
    }

    public int book(int start, int end) {
        add(start, end, root);
        return res;
    }

    private void add(int start, int end, SegmentTree root) {
        if (root.m != -1) {
            if (start >= root.m) add(start, end, root.right);
            else if (end <= root.m) add(start, end, root.left);
            else {
                add(start, root.m, root.left);
                add(root.m, end, root.right);
            }
            return;
        }

        if (start == root.l && end == root.r) {
            root.cnt++;
            res = Math.max(res, root.cnt);
        }
        else if (start == root.l) {
            root.m = end;
            root.left = new SegmentTree(start, root.m, root.cnt + 1);
            root.right = new SegmentTree(root.m, root.r, root.cnt);
            res = Math.max(res, root.cnt + 1);
        }
        else if (end == root.r) {
            root.m = start;
            root.left = new SegmentTree(root.l, root.m, root.cnt);
            root.right = new SegmentTree(root.m, root.r, root.cnt + 1);
            res = Math.max(res, root.cnt + 1);
        }
        else {
            root.m = start;
            root.left = new SegmentTree(root.l, root.m, root.cnt);
            root.right = new SegmentTree(root.m, root.r, root.cnt);
            add(start, end, root.right);
        }
    }
}

class SegmentTree {
    int l;
    int r;
    int m; // m : 分割点,如果尚未分割则为-1。
    int cnt;
    SegmentTree left;
    SegmentTree right;

    SegmentTree(int l, int r, int cnt) {
        this.l = l;
        this.r = r;
        this.m = -1;
        this.cnt = cnt;
        this.left = null;
        this.right = null;
    }
}

 

六、Interval List Intersections

问题描述:

问题求解:

如何快速判断是否相交呢?

    public int[][] intervalIntersection(int[][] A, int[][] B) {
        List<int[]> res = new ArrayList<>();
        int i = 0;
        int j = 0;
        while (i < A.length && j < B.length) {
            int s = Math.max(A[i][0], B[j][0]);
            int e = Math.min(A[i][1], B[j][1]);
            if (s <= e) res.add(new int[]{s, e});
            if (A[i][1] < B[j][1]) i++;
            else j++;
        }
        int[][] rst = new int[res.size()][2];
        for (i = 0; i < res.size(); i++) {
            rst[i][0] = res.get(i)[0]; 
            rst[i][1] = res.get(i)[1];
        }
        return rst;
    }

  

  

 

posted @ 2018-09-07 09:05  hyserendipity  阅读(1046)  评论(0编辑  收藏  举报