找出两个数字范围是否相交的最佳方法是什么?
我的号码范围 3023-7430 ,现在我想测试下列哪个数字范围:< 3000,3000-6000,6000-8000,8000-10000,> 10000。答案应该是 3000-6000 和 6000-8000 。
用任何编程语言执行此操作的有效数学方法是什么?
答案 0 :(得分:20)
只是伪代码猜测:
Set<Range> determineIntersectedRanges(Range range, Set<Range> setofRangesToTest)
{
Set<Range> results;
foreach (rangeToTest in setofRangesToTest)
do
if (rangeToTest.end <range.start) continue; // skip this one, its below our range
if (rangeToTest.start >range.end) continue; // skip this one, its above our range
results.add(rangeToTest);
done
return results;
}
答案 1 :(得分:6)
我会创建一个Range类,并给它一个方法boolean intersects(Range)。然后你可以做一个
foreach(Range r : rangeset) { if (range.intersects(r)) res.add(r) }
或者,如果为了清晰起见使用了一些Java 8风格的函数式编程:
rangeset.stream().filter(range::intersects).collect(Collectors.toSet())
交叉点本身就像
this.start <= other.end && this.end >= other.start
答案 2 :(得分:3)
这在很大程度上取决于你的范围。范围可以大或小,并且可以是群集的或不群集的。如果你有大的聚簇范围(想想“所有正32位整数可以除以2),那么使用Range(lower,upper)的简单方法将不会成功。
我想我可以说以下内容: 如果您的范围很小(聚类或不聚类在这里无关紧要),请考虑位向量。这些小动物在联合,交集和成员测试方面都非常快速,即使迭代所有元素可能需要一段时间,具体取决于大小。此外,因为它们只对每个元素使用一个位,所以它们非常小,除非你向它们抛出大范围。
如果你有更少,更大的范围,那么其他人描述的类范围就足够了。该类具有较低和较高的属性,并且交集(a,b)基本上是b.upper&lt; a.lower或a.upper&gt; b.lower。联合和交集可以在单个范围的恒定时间内实现,对于复杂范围,时间随着子范围的数量而增长(因此您不希望没有太多的小范围)
如果你有一个巨大的空间,你的数字可以,并且范围分布在讨厌的时尚,你应该看看二元决策图(BDDs)。这些漂亮的图表有两个终端节点,True和False以及输入的每个位的决策节点。决策节点有一个它看起来的位和两个后续的图节点 - 一个用于“位是一个”而一个用于“位是零”。鉴于这些条件,您可以在很小的空间内编码大范围。任意大数的所有正整数都可以在图中的3个节点中编码 - 基本上是最低有效位的单个决策节点,在1上变为False,在0上变为True。
Intersection和Union是非常优雅的递归算法,例如,交集基本上在每个BDD中占用两个相应的节点,遍历1-edge直到某些结果弹出并检查:如果其中一个结果是False-Terminal,在结果BDD中为False-terminal创建1分支。如果两者都是True-Terminal,则在结果BDD中为True-terminal创建1分支。如果是其他内容,请在结果BDD中为此内容创建一个分支。在那之后,一些最小化开始(如果节点的0和1分支在BDD /终端之后转移到同一个,移除它并将传入的转换拉到目标)并且你是金色的。我们甚至更进一步,我们致力于在BDD上模拟添加整数集,以便增强价值预测以优化条件。
这些注意事项意味着您的操作受数字范围内的位数限制,即log_2(MAX_NUMBER)。想想看,你可以在几乎恒定的时间内交叉任意64位整数集。
更多信息可以在Wikipedia和参考文件中找到。
此外,如果误报是可以忍受的,并且您只需要存在检查,则可以查看Bloom过滤器。布隆过滤器使用散列向量来检查元素是否包含在所表示的集合中。交叉口和联盟是恒定的时间。这里的主要问题是如果你过多地填充bloom-filter,你会得到越来越多的假阳性率。 例如,再次在Wikipedia中提供信息。
哈希,设定代表是一个有趣的领域。 :)
答案 3 :(得分:1)
在python中
class nrange(object):
def __init__(self, lower = None, upper = None):
self.lower = lower
self.upper = upper
def intersection(self, aRange):
if self.upper < aRange.lower or aRange.upper < self.lower:
return None
else:
return nrange(max(self.lower,aRange.lower), \
min(self.upper,aRange.upper))
答案 4 :(得分:0)
如果您使用的是Java Commons Lang Range 有个 overlapsRange(范围范围)方法。