我想合并一些这样的间隔:
>>> ranges = [(30, 45), (40, 50), (10, 50), (60, 90), (90, 100)]
>>> merge(ranges)
[(10, 50), (60, 100)]
我不在cs领域。我知道如何通过迭代来做到这一点,但想知道是否有一种更有效的“自上而下”的方法来更有效地合并它们,可能使用一些特殊的数据结构?
感谢。
答案 0 :(得分:3)
间隔树肯定有效,但它比你需要的更复杂。间隔树是一种“在线”解决方案,因此它允许您添加一些间隔,查看并集,添加更多间隔,再次查看等。
如果你有所有的时间间隔,你可以做一些更简单的事情:
从输入
开始范围= [(30,45),(40,50),(10,50)]
将范围列表转换为端点列表。如果你有范围(A,B),你将它转换为两个端点:(A,0)将是左端点,(B,1)将是正确的端点。
端点= [(30,0),(45,1),(40,0),(50,1),(10,0),(50,1)]
对端点进行排序
端点= [(10,0),(30,0),(40,0),(45,1),(50,1),(50,1)]
通过端点列表向前扫描。当您看到左端点时递增计数器,并在看到正确的端点时递减计数器。只要计数器达到0,就会关闭当前的合并间隔。
此解决方案可以在几行中实现。
答案 1 :(得分:2)
是的,有效的方法是使用interval tree。
答案 2 :(得分:0)
C#中的以下算法可以满足您的需求。它使用DateTime
区间范围,但您可以随意调整它。一旦集合按升序开始顺序排序,如果下一个间隔的开始位于前一个间隔的结尾或之前,它们会重叠,并且如果需要,您可以向外延长结束时间。否则它们不会重叠,您可以将之前的一个保存到结果中。
public static List<DateTimeRange> MergeTimeRanges(List<DateTimeRange> inputRanges)
{
List<DateTimeRange> mergedRanges = new List<DateTimeRange>();
// Sort in ascending start order.
inputRanges.Sort();
DateTime currentStart = inputRanges[0].Start;
DateTime currentEnd = inputRanges[0].End;
for (int i = 1; i < inputRanges.Count; i++)
{
if (inputRanges[i].Start <= currentEnd)
{
if (inputRanges[i].End > currentEnd)
{
currentEnd = inputRanges[i].End; // Extend range.
}
}
else
{
// Save current range to output.
mergedRanges.Add(new DateTimeRange(currentStart, currentEnd));
currentStart = inputRanges[i].Start;
currentEnd = inputRanges[i].End;
}
}
mergedRanges.Add(new DateTimeRange(currentStart, currentEnd));
return mergedRanges;
}