我有一系列范围:
[[39600..82800], [39600..70200],[70200..80480]]
我需要确定是否存在重叠。在ruby中这样做的简单方法是什么?
在上述情况下,输出应为'重叠'。
答案 0 :(得分:8)
这是一个非常有趣的谜题,特别是如果你关心表演。
如果范围只有两个,那么这是一个相当简单的算法,ActiveSupport
overlaps?
扩展也包含了这个算法。
def ranges_overlap?(r1, r2)
r1.cover?(r2.first) || r2.cover?(r1.first)
end
如果你想比较多个范围,那么这是一个相当有趣的算法练习。
您可以遍历所有范围,但是您需要将每个范围与所有其他可能性进行比较,但这是一种具有指数成本的算法。
更有效的解决方案是order the ranges并执行二进制搜索,或使用数据结构(例如树)来计算重叠。
Interval tree页面中也解释了此问题。计算重叠主要包括找到树的交叉点。
答案 1 :(得分:3)
考虑一下:
class Range
include Comparable
def <=>(other)
self.begin <=> other.begin
end
def self.overlap?(*ranges)
edges = ranges.sort.flat_map { |range| [range.begin, range.end] }
edges != edges.sort.uniq
end
end
Range.overlap?(2..12, 6..36, 42..96) # => true
备注强>:
答案 2 :(得分:2)
这不是一种方法吗?
def any_overlapping_ranges(array_of_ranges)
array_of_ranges.sort_by(&:first).each_cons(2).any?{|x,y|x.last>y.first}
end
p any_overlapping_ranges([50..100, 1..51,200..220]) #=> True
答案 3 :(得分:1)
为了简单和可读性,我建议采用这种方法:
def overlaps?(ranges)
ranges.each_with_index do |range, index|
(index..ranges.size).each do |i|
nextRange = ranges[i] unless index == i
if nextRange and range.to_a & nextRange.to_a
puts "#{range} overlaps with #{nextRange}"
end
end
end
end
r = [(39600..82800), (39600..70200),(70200..80480)]
overlaps?(r)
和输出:
ruby ranges.rb
39600..82800 overlaps with 39600..70200
39600..82800 overlaps with 70200..80480
39600..70200 overlaps with 70200..80480