如果您有n个范围类似于[1,4.5]
的范围,那么如何在O(nlogn)
时间内找到任何索引是否包含另一个索引?注意:如果[x,y]
和[a,b]
,x >= a
将完全包含b <= y
。
这似乎可以与合并排序类似地进行,您可以检查是否有任何范围在范围总量的每一半中包含另一个范围,然后比较任一半中的任何范围是否包含另一半的范围。我的问题是,我无法找到O(n)
方法来完成最后一部分。我猜我会以某种方式将某些范围结合起来,但我无法想到如何。
答案 0 :(得分:10)
这是一个简单的算法,似乎在O(nlogn)
时间内运行:
首先排序 n
范围的集合,使用范围的开始值,从最小到最大。如果您在此处使用合并排序,则应在O(nlogn)
时间内运行。正如@Aivean指出的那样,当两个或多个范围具有相等的起始值时,需要考虑一个边缘情况。在这种情况下,此类范围应按降序顺序的范围结束值排序。
接下来沿着这组范围从最小的第一个值到最高值,并执行以下操作:
for (range r : ranges[1 to N-1]) {
if (end value for range r+1 <= end value for range r) {
// then range r+1 is completely contained within some previous range
return true;
}
}
第二步是单O(n)
次传递,不会改变第一步的整体O(nlogn)
运行时间。
这是一个图形说明,显示算法如何工作。范围已使用范围的开始值进行排序,从最小到最大。应该清楚的是,所有必要的是从左向右走,并按顺序比较每对范围的结束值。
1. |------|
2. |-------|
3. |-------|
4. |------|
5. |-------|
6. |-------|
感谢在检查范围#3时我们不需要检查超出范围#2的任何东西。这样做的原因是,为了使范围#1包含范围#3,它必须将扩展到范围#2之外,这意味着它已经包含范围#2。但这意味着算法已经返回true,因此我们不需要检查这种可能性。
另请注意,范围#3和#4按其结束值按降序排序。这确保算法将检测范围#4完全包含在范围#3内。您可以颠倒范围#3和#4的顺序,以查看在起始值为平局的情况下可能存在问题。