最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

algorithm - Overlap Removal with Bounding Interval - Stack Overflow

programmeradmin5浏览0评论

I have a list of Intervals and a second interval which is used to bound the other intervals. For example:

[[4,7],[5,7]]
bounded by [0,10]

I need an algorithm, which is able to shift the intervals of the list with as little motion as possible so that no interval is overlapping each other and every interval is in the boundary.

Output: [[4,7],[7,9]]

other Examples:

[[6,8],[6,9]]
bounded by [0,10]
Output: [[5,7],[7,10]]
[[0,1],[5,6],[6,8],[6,9]]
bounded by [0,10]
Output: [[0,1],[4,5],[5,7],[7,10]]

I tried to write this algorithm in C#, but when 3 or more intervals are near the boundary, it gets stuck in a infinite recursion.

public class Bookshelf
{
    public List<Tuple<int, int>> Intervals {  get; private set; }
    public Tuple<int, int> Boundary {  get; private set; }

    public Bookshelf(List<Tuple<int, int>> intervals, Tuple<int, int> boundary)
    {
        Intervals=intervals;
        Boundary=boundary;
        Intervals.Sort((a, b) =>
        {
            int compareStart = a.Item1.CompareTo(b.Item1);
            return compareStart != 0 ? compareStart : a.Item2.CompareTo(b.Item2);
        });
        foreach (var overlap in FindOverlaps())
            HandleOverlap(overlap);
    }
    public static int Range(Tuple<int, int> interval) => interval.Item2 - interval.Item1;
    public bool IsEnoughSpace(Tuple<int, int> interval) => (Intervals.Sum(item => Range(item)) + Range(interval)) <= Range(Boundary);
    public int IsInBound(Tuple<int, int> interval) => (Boundary.Item1 <= interval.Item1) && (Boundary.Item2 >= interval.Item2) ? 0 : (Boundary.Item1 > interval.Item1) ? -1 : 1;
    public void AddInterval(Tuple<int, int> interval)
    {
        if (!IsEnoughSpace(interval)) throw new Exception("Not enough space");
        if (IsInBound(interval) != 0) throw new Exception("Not in Bound");
        Intervals.Add(interval);
        Intervals.Sort((a, b) =>
        {
            int compareStart = a.Item1.CompareTo(b.Item1);
            return compareStart != 0 ? compareStart : a.Item2.CompareTo(b.Item2);
        });
        foreach(var overlap in FindOverlaps())
            HandleOverlap(overlap);
    }
    private List<Tuple<Tuple<int, int>, Tuple<int, int>>> FindOverlaps()
    {
        List<Tuple<Tuple<int, int>, Tuple<int, int>>> overlaps = new List<Tuple<Tuple<int, int>, Tuple<int, int>>>();
        int currentStart = Intervals[0].Item1;
        int currentEnd = Intervals[0].Item2;
        for (int i = 1; i < Intervals.Count; i++)
        {
            int start = Intervals[i].Item1;
            int end = Intervals[i].Item2;
            if (start < currentEnd && currentStart < end)
            {
                overlaps.Add(Tuple.Create(Intervals[i-1], Intervals[i]));
                currentEnd = Math.Max(currentEnd, end);
            }
            else
            {
                currentStart = start;
                currentEnd = end;
            }
        }
        return overlaps;
    }

    private void HandleOverlap(Tuple<Tuple<int, int>, Tuple<int, int>> pair)
    {
        Tuple<int, int> lower = pair.Item1;
        Tuple<int, int> upper = pair.Item2;

        int upperRange = Range(upper);
        int lowerRange = Range(lower);
        Tuple<int, int> temp = Tuple.Create(lower.Item2, lower.Item2 + upperRange);
        if (IsInBound(temp) == 0)
        {
            int idx = Intervals.IndexOf(upper);
            Intervals[idx] = temp;
            foreach (var overlap in FindOverlaps())
                HandleOverlap(overlap);
        }
        else if(IsInBound(temp) < 0)
        {
            int idx = Intervals.IndexOf(upper);
            Intervals[idx] = Tuple.Create(lower.Item2, lower.Item2 + upperRange);
            idx = Intervals.IndexOf(lower);
            Intervals[idx] = Tuple.Create(Boundary.Item1, Boundary.Item1 + lowerRange);
            foreach (var overlap in FindOverlaps())
                HandleOverlap(overlap);
        } 
        else
        {
            int idx = Intervals.IndexOf(upper);
            Intervals[idx] = Tuple.Create(Boundary.Item2 - upperRange, Boundary.Item2);
            idx = Intervals.IndexOf(lower);
            Intervals[idx] = Tuple.Create(upper.Item1 - lowerRange, upper.Item1);
            foreach (var overlap in FindOverlaps())
                HandleOverlap(overlap);
        }
    }

If you know the solution, can also write it in pseudocode.

EDIT: I also tried other ways to solve this issue.

public Bookshelf(List<Tuple<int, int>> intervals, Tuple<int, int> boundary)
{
    Intervals = intervals;
    Boundary = boundary;
    HandleOverlap();
}
private void HandleOverlap()
{
    Intervals.Sort((a, b) => a.Item1.CompareTo(b.Item1));
    List<Tuple<int, int>> adjustedIntervals = new List<Tuple<int, int>>();
    int lastEnd = Boundary.Item1;
    foreach (var interval in Intervals)
    {
        int start = interval.Item1;
        int end = interval.Item2;
        if (start < lastEnd)
        {
            start = lastEnd;
            end = start + (interval.Item2 - interval.Item1);
        }
        if (end > Boundary.Item2)
        {
            end = Boundary.Item2;
            start = end - (interval.Item2 - interval.Item1);
        }
        lastEnd = end;
        adjustedIntervals.Add(Tuple.Create(start, end));
    }
    Intervals = adjustedIntervals;
}

This Approach worked better than my attempt before. However it cant remove overlaps at the upper bound. Here is example I used

[(5,9),(7,10)] bounded by (0,10)
Expected Output: [(3,7),(7,10)]
Actual Output: [(5,9),(7,10)]
发布评论

评论列表(0)

  1. 暂无评论