查找数字范围交叉点

时间:2008-10-22 08:30:38

标签: math

找出两个数字范围是否相交的最佳方法是什么?

我的号码范围 3023-7430 ,现在我想测试下列哪个数字范围:< 3000,3000-6000,6000-8000,8000-10000,> 10000。答案应该是 3000-6000 6000-8000

用任何编程语言执行此操作的有效数学方法是什么?

5 个答案:

答案 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(范围范围)方法。