我想有效地确定范围列表是否涵盖给定范围。例如,范围[(0-3),(3-5),(4-8),(6-10)]的列表涵盖范围(0-10),而[(5-10),(0- 3)]不。该列表可以包含重叠,并且不一定要排序。
我尝试实现如下所示的Continuous
函数,该函数检查字节范围片是否包含给定的start
和end
传递范围。
type byteRange struct {
start int64
end int64
}
type byteRanges []*byteRange
func (brs byteRanges) Len() int {
return len(brs)
}
func (brs byteRanges) Swap(i, j int) {
brs[i], brs[j] = brs[j], brs[i]
}
func (brs byteRanges) Less(i, j int) bool {
return brs[i].start < brs[j].start
}
func (brs byteRanges) Continuous(start int64, end int64) bool {
curPos := start
sort.Sort(brs)
for _, br := range brs {
if br.start > curPos+1 {
return false
}
if curPos < br.end {
curPos = br.end
}
if curPos >= end {
return true
}
}
return false
}
该函数的行为正确,但是在处理大量范围时以及经常调用时,它的性能不是很好。有人可以推荐可以加快这种逻辑速度的算法/实现吗?
答案 0 :(得分:2)
由于您将在同一组范围内重复调用Continuous
,因此,最好创建一个Condense
方法(或任何您想调用的方法),该方法将切分并返回一个范围已排序且所有重叠范围已合并的新切片。您只需为任意一组给定的范围调用Condense
一次。 Continuous
然后可以要求仅在Condense
的结果上调用它。 (要强制执行此要求,最好让Condense
实际上返回一个自定义类型的struct
,该自定义类型只是一个切片的包装,并仅在其上定义Continuous
struct
类型。为方便起见,您可以定义一个单独的Continuous
方法,可以直接在切片上调用 ,该方法调用Condense
并然后是Continuous
。这种便利方法当然会再次变慢,但是对于只被检查一次的集合可能会很便利。)
Condense
中的合并逻辑非常简单:
start
对范围进行排序。result
的新切片。prevRange
初始化为第一个范围。prevRange.end + 1
开始,请将prevRange
添加到result
,然后将prevRange
设置为当前范围。prevRange.end
之后结束,请将prevRange.end
设置为当前范围的end
。prevRange
添加到result
。 Continuous
中的逻辑现在可以是:
start
小于或等于start
的最后一个范围。end
大于或等于end
,则返回true
;否则,返回false
。答案 1 :(得分:0)
更简单的解决方案?
package main
import (
"fmt"
"sort"
)
type byteRange struct {
start int64
end int64
}
type byteRanges []*byteRange
func (brs byteRanges) Continuous(start int64, end int64) bool {
sort.Slice(brs, func(i, j int) bool {
return brs[i].start < brs[j].start
})
var (
longestReach int64
in bool
)
for _, br := range brs {
if !in {
// first br satrts laying over the target
if br.start <= start && br.end >= start {
longestReach = br.end
in = true
}
continue
}
if in && longestReach < br.start-1 {
break
}
if longestReach < br.end {
longestReach = br.end
}
}
return in && longestReach >= end
}
func main() {
brs := byteRanges{{5, 9}, {6, 10}}
fmt.Println(brs.Continuous(8, 10))
}