排除重叠间隔 [英] Exclude overlapping intervals

查看:96
本文介绍了排除重叠间隔的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个间隔列表。我想从列表2中已经存在的list1中删除所有时间。
示例:
List1:

I have two lists of intervals. I would like to remove all times from list1 that already exists in list2. Example: List1:


[(0,10),(15,20)]

[(0,10),(15,20)]

List2:


[(2,3) ,(5,6)]

[(2,3),(5,6)]

输出:


[(0,2),(3,5),(6,10),(15,20)]

[(0,2),(3,5),(6,10),(15,20)]

任何提示?

当时试图删除一个间隔,但似乎我需要采取不同的方法:

Tried to remove one interval at the time but it seems like I need to take a different approach:

public List<Interval> removeOneTime(Interval interval, Interval remove){
    List<Interval> removed = new LinkedList<Interval>();
    Interval overlap = interval.getOverlap(remove);
    if(overlap.getLength() > 0){
        List<Interval> rms = interval.remove(overlap);
        removed.addAll(rms);
    }
    return removed;
}


推荐答案

我会解决这个问题扫描线算法。间隔的起点和终点是放在优先级队列中的事件。您只需从左向右移动,在每个事件处停止,并根据该事件更新当前状态。

I would approach this problem with a sweep line algorithm. The start and end points of the intervals are events, that are put in a priority queue. You just move from left to right, stop at every event, and update the current status according to that event.

我做了一个小实现,其中我使用以下内容 Interval 类,只是为了简单:

I made a small implementation, in which I use the following Interval class, just for simplicity:

public class Interval {
    public int start, end;

    public Interval(int start, int end) {       
        this.start = start;
        this.end = end;
    }

    public String toString() {
        return "(" + start + "," + end + ")";
    }
}

前面提到的事件点由以下类表示:

The event points mentioned earlier are represented by the following class:

public class AnnotatedPoint implements Comparable<AnnotatedPoint> {
    public int value;
    public PointType type;

    public AnnotatedPoint(int value, PointType type) {
        this.value = value;
        this.type = type;
    }

    @Override
    public int compareTo(AnnotatedPoint other) {
        if (other.value == this.value) {
            return this.type.ordinal() < other.type.ordinal() ? -1 : 1;
        } else {
            return this.value < other.value ? -1 : 1;
        }
    }

    // the order is important here: if multiple events happen at the same point,
    // this is the order in which you want to deal with them
    public enum PointType {
        End, GapEnd, GapStart, Start
    }
}

现在,剩下的就是构建队列并进行扫描,如下面的代码所示

Now, what remains is building the queue and doing the sweep, as shown in the code below

public class Test {

    public static void main(String[] args) {        
        List<Interval> interval = Arrays.asList(new Interval(0, 10), new Interval(15, 20));
        List<Interval> remove = Arrays.asList(new Interval(2, 3), new Interval(5, 6));

        List<AnnotatedPoint> queue = initQueue(interval, remove);       
        List<Interval> result = doSweep(queue);

        // print result
        for (Interval i : result) {
            System.out.println(i);
        }
    }

    private static List<AnnotatedPoint> initQueue(List<Interval> interval, List<Interval> remove) {
        // annotate all points and put them in a list
        List<AnnotatedPoint> queue = new ArrayList<>();
        for (Interval i : interval) {
            queue.add(new AnnotatedPoint(i.start, PointType.Start));
            queue.add(new AnnotatedPoint(i.end, PointType.End));
        }
        for (Interval i : remove) {
            queue.add(new AnnotatedPoint(i.start, PointType.GapStart));
            queue.add(new AnnotatedPoint(i.end, PointType.GapEnd));
        }

        // sort the queue
        Collections.sort(queue);

        return queue;
    }

    private static List<Interval> doSweep(List<AnnotatedPoint> queue) {
        List<Interval> result = new ArrayList<>();

        // iterate over the queue       
        boolean isInterval = false; // isInterval: #Start seen > #End seen
        boolean isGap = false;      // isGap:      #GapStart seen > #GapEnd seen
        int intervalStart = 0;  
        for (AnnotatedPoint point : queue) {
            switch (point.type) {
            case Start:
                if (!isGap) {                   
                    intervalStart = point.value;
                }
                isInterval = true;
                break;
            case End:
                if (!isGap) {                   
                    result.add(new Interval(intervalStart, point.value));
                }
                isInterval = false;
                break;
            case GapStart:
                if (isInterval) {                   
                    result.add(new Interval(intervalStart, point.value));
                }               
                isGap = true;
                break;
            case GapEnd:
                if (isInterval) {
                    intervalStart = point.value;
                }
                isGap = false;
                break;
            }
        }

        return result;
    }
}

这导致:

(0,2)
(3,5)
(6,10)
(15,20)

这篇关于排除重叠间隔的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆