如何获得两个范围的重叠范围

时间:2011-09-15 22:56:50

标签: c# algorithm

我在区间[1-15]

中有以下范围

我想找到1和1之间的重叠范围。 2。

Person1 [1,3] [5,10] Person2 [2,4] [8,15]

在这里,我应该得到一个范围列表,[2,3],[8,10]。

到目前为止我发现的是按person1的范围循环,然后按person2的范围循环,然后是每个范围的每个元素,然后使用条件测试。 这个解决方案不满足我,因为它是O(n)。更多元素的范围,我的算法将为每个范围的每个元素循环更多,如果我想看到这些范围之间的切换,则需要时间

Person1:[100000; 150000]和[90000; 140000]。 人2:[105000; 110000]和[130000; 140050]

请注意,范围在我的代码中表示为:

public class Range{
    public int Start {get;set;}
    public int End {get;set;}
}

那么找到重叠范围的最有效方法是什么?

任何帮助都将不胜感激。

PS:这里有类似的问题How to find range overlap in python?,但我不懂python代码。

4 个答案:

答案 0 :(得分:3)

对范围的开始和结束进行排序..保持信息以及是否为范围开始或结束......对于您的示例,您将得到此信息:

1 start
2 start
3 end
4 end
5 start
8 start
10 end
15 end

现在循环遍历这些点并保留一个计数器.. + 1表示结束的开始-1。此计数器是任何时候重叠段的数量。如果您想要每次增加或减少计数器时需要测试的边界。如果你将它从1增加到2,这是一个重叠范围的开始..重叠范围的结束将是你将计数器从2减少到1

马丁

答案 1 :(得分:1)

感谢您的澄清。这样的事情......

public static IList<Range> GetListIntersections(IList<Range> rangeList1, IList<Range> rangeList2)
{
    var intersection = new List<Range>();

    //add intersection of each range
    foreach (var x in rangeList1)
    {
        foreach (var y in rangeList2)
        {
            var intersect = GetIntersection(x, y);
            if (intersect != null)
            {
                intersection.Add(intersect);
            }
        }
    }

    //remove ranges that are subsets of other ranges
    intersection.RemoveAll(x => intersection.Any(y => y != x && y.Start >= x.Start && y.End <= x.End));

    return intersection;
}

public static Range GetIntersection(Range range1, Range range2)
{
    int greatestStart = range1.Start > range2.Start ? range1.Start : range2.Start;
    int smallestEnd = range1.End < range2.End ? range1.End : range2.End;

    //no intersection
    if (greatestStart > smallestEnd)
    {
        return null;
    }

    return new Range { Start = greatestStart, End = smallestEnd };
}

答案 2 :(得分:1)

查看mergesort算法的合并步骤。如果对每个人的范围进行排序,则可以调整此方法以非常容易地计算重叠。

Loop
   Get the range that starts next (R1)
   if the next range of the other person (R2) starts before R1 ends
      Add the range from begin of R2 and min( end of R1 end of R2 ) to results
   Increase the counter for the person which gave you R1

如果已知您的范围是非相邻的(即,如果连续范围之间始终至少有一个数字)。解决方案也将是。否则,您可能需要额外的压缩步骤以确保将相邻范围放入一个范围。

好消息是,这适用于任何有序类型而不仅仅是整数,并且您可以非常快速地交叉任意数量的范围(O(n + m))。

答案 3 :(得分:0)

我不明白你是如何按'person1的范围循环,然后按person2的范围循环' - 我不确定这是什么意思而不看代码。

我看不出你会如何比O(n)更好,但你只能在范围内迭代一次。更好的数据结构可能是bool[]BitArray

var person1 = new bool[15] { /* set values */ };
var person2 = new bool[15] { /* set values */ };

var overlap = new bool[15];

for (int i = 0; i < 15; i++)
{
    overlap[i] = person1[i] && person2[i];
}