我有一组不重叠的,不相邻的区间,例如[{10,15},{30,35},{20,25}]。它们没有排序,但如果需要,我可以对它们进行排序。
现在,我得到了一些新的区间,例如{5,32},并希望生成一组新的区间来描述差异:这个新区间所覆盖的范围不在该集合中。在这个例子中,答案是:[{5,9},{16,19},{26,29}]。
计算这个的快速算法是什么?请注意,集合中通常有1个,有时有2个,很少有3个或更多项目,因此我想针对这种情况进行优化。
对于上下文,下面是从输入的开始-结束数据流中最初创建集合的代码,我在其中进行合并:
type Interval struct {
start int
end int
}
func (i *Interval) OverlapsOrAdjacent(j Interval) bool {
return i.end+1 >= j.start && j.end+1 >= i.start
}
func (i *Interval) Merge(j Interval) bool {
if !i.OverlapsOrAdjacent(j) {
return false
}
if j.start < i.start {
i.start = j.start
}
if j.end > i.end {
i.end = j.end
}
return true
}
type Intervals []Interval
func (ivs Intervals) Len() int { return len(ivs) }
func (ivs Intervals) Swap(i, j int) { ivs[i], ivs[j] = ivs[j], ivs[i] }
func (ivs Intervals) Less(i, j int) bool { return ivs[i].start < ivs[j].start }
func (ivs Intervals) Merge(iv Interval) Intervals {
ivs = append(ivs, iv)
merged := make(Intervals, 0, len(ivs))
for _, iv := range ivs {
for i := 0; i < len(merged); {
if iv.Merge(merged[i]) {
merged = append(merged[:i], merged[i+1:]...)
} else {
i++
}
}
merged = append(merged, iv)
}
return merged
}
func (ivs Intervals) MergeUsingSort(iv Interval) Intervals {
ivs = append(ivs, iv)
sort.Sort(ivs)
merged := make(Intervals, 0, len(ivs))
merged = append(merged, ivs[0])
for i := 1; i < len(ivs); i++ {
last := len(merged) - 1
if !merged[last].Merge(ivs[i]) {
merged = append(merged, ivs[i])
}
}
return merged
}
func (ivs Intervals) Difference(iv Interval) Intervals {
// ???
return ivs
}
func main() {
var ivs Intervals
for _, input := range inputsFromSomewhere { // in reality, I don't have all these inputs at once, they come in one at a time
iv := Interval{input.start, input.end}
diffs := ivs.Difference(iv) // not yet implemented...
// do something with diffs
ivs = ivs.Merge(iv)
}
}
我发现上述间隔。Merge()比MergeUsingSort()快2倍,所以我想知道是否还有一种简单的非排序方式来回答我的问题。
为了回答我自己的问题,这里是我对Difference()的实现,它(在我的输入数据上)比JimB要求排序的建议更快。
func (i *Interval) Overlaps(j Interval) bool {
return i.End >= j.Start && j.End >= i.Start
}
func (i *Interval) Difference(j Interval) (left *Interval, right *Interval, overlapped bool) {
if !i.Overlaps(j) {
return
}
overlapped = true
if j.Start < i.Start {
left = &Interval{j.Start, i.Start - 1}
}
if j.End > i.End {
right = &Interval{i.End + 1, j.End}
}
return
}
func (ivs Intervals) Difference(iv Interval) (diffs Intervals) {
diffs = append(diffs, iv)
for _, prior := range ivs {
for i := 0; i < len(diffs); {
if left, right, overlapped := prior.Difference(diffs[i]); overlapped {
if len(diffs) == 1 {
diffs = nil
} else {
diffs = append(diffs[:i], diffs[i+1:]...)
}
if left != nil {
diffs = append(diffs, *left)
}
if right != nil {
diffs = append(diffs, *right)
}
} else {
i++
}
}
if len(diffs) == 0 {
break
}
}
return
}
它适用于我尝试过的数据,尽管我有点担心我可能错过了一个边缘案例,因为它得到了错误的答案。
问答代码不完整,无法编译。没有基准。快速浏览一下代码,它可能效率很低。
间隔的可用代码。进行间隔测试。go来自https://github.com/VertebrateResequencing/wr/tree/develop/minfys.
让我们首先为间隔差示例编写一个基准测试。
package minfys
import (
"fmt"
"testing"
)
// Example
var (
xA = Intervals{{10, 15}, {30, 35}, {20, 25}}
xB = Interval{5, 32}
xD = Intervals{{5, 9}, {16, 19}, {26, 29}}
xR = Intervals{}
)
func BenchmarkExample(b *testing.B) {
b.ReportAllocs()
a := make(Intervals, len(xA))
b.ResetTimer()
for i := 0; i < b.N; i++ {
copy(a, xA)
xR = a.Difference(xB)
}
b.StopTimer()
if fmt.Sprint(xD) != fmt.Sprint(xR) {
b.Fatal(xD, xR)
}
}
接下来,编写一个差分方法。
package minfys
func (a Intervals) Difference(b Interval) Intervals {
// If A and B are sets, then the relative complement of A in B
// is the set of elements in B but not in A.
// The relative complement of A in B is denoted B ∖ A:
// B \ A = {x ∈ A | x ∉ B}
// B \ A = B ∩ A'
//
// For example. d = a\b,
// a: [{10, 15}, {30, 35}, {20, 25}]
// b: {5,32}
// d: [{5,9}, {16,19}, {26,29}]
// The elements of set a are non-overlapping, non-adjacent,
// and unsorted intervals.
if len(a) <= 0 {
return Intervals{b}
}
d := make(Intervals, 0, 3)
for ; len(a) > 0; a = a[1:] {
for i := 1; i < len(a); i++ {
if a[i].Start < a[0].Start {
a[i], a[0] = a[0], a[i]
}
}
if b.Start < a[0].Start {
if b.End < a[0].Start {
d = append(d, b)
break
}
d = append(d, Interval{b.Start, a[0].Start - 1})
b.Start = a[0].Start
}
if b.End <= a[0].End {
break
}
if b.Start <= a[0].End {
b.Start = a[0].End + 1
}
if len(a) == 1 {
if b.Start <= a[0].End {
b.Start = a[0].End + 1
}
d = append(d, b)
break
}
}
return d
}
现在,对差分法进行基准测试。
BenchmarkExample-4 20000000 62.4 ns/op 48 B/op 1 allocs/op
sbs写了一个差异方法。
// Interval struct is used to describe something with a start and end. End must
// be greater than start.
type Interval struct {
Start int64
End int64
}
// Overlaps returns true if this interval overlaps with the supplied one.
func (i *Interval) Overlaps(j Interval) bool {
// https://nedbatchelder.com/blog/201310/range_overlap_in_two_compares.html
return i.End >= j.Start && j.End >= i.Start
}
// Intervals type is a slice of Interval.
type Intervals []Interval
// Difference returns any portions of iv that do not overlap with any of our
// intervals. Assumes that all of our intervals have been Merge()d in.
func (ivs Intervals) Difference(iv Interval) (diffs Intervals) {
diffs = append(diffs, iv)
for _, prior := range ivs {
for i := 0; i < len(diffs); {
if left, right, overlapped := prior.Difference(diffs[i]); overlapped {
if len(diffs) == 1 {
diffs = nil
} else {
diffs = append(diffs[:i], diffs[i+1:]...)
}
if left != nil {
diffs = append(diffs, *left)
}
if right != nil {
diffs = append(diffs, *right)
}
} else {
i++
}
}
if len(diffs) == 0 {
break
}
}
return
}
基准sbs的差分法。
BenchmarkExample-4 5000000 365 ns/op 128 B/op 4 allocs/op
彼得索的差分法要快得多。
old.txt (sbs) versus new.txt (peterSO):
benchmark old ns/op new ns/op delta
BenchmarkExample-4 365 62.4 -82.90%
benchmark old allocs new allocs delta
BenchmarkExample-4 4 1 -75.00%
benchmark old bytes new bytes delta
BenchmarkExample-4 128 48 -62.50%
这只是一个开始。可能还有其他改进。
在interval_test.go
中有一些错误。ShouldBeNil
代表指针;ShouldBeAir ty
代表集合。ShouldResemble
不处理集合相等(包含相同元素的两个集合是相同的集合)。更改ShouldResemble
顺序以匹配实现相关顺序。
$ go test
..........................................................................................................................x......................................................x................x
Failures:
* interval_test.go
Line 247:
Expected: nil
Actual: '[]'
* interval_test.go
Line 375:
Expected: 'minfys.Intervals{minfys.Interval{Start:5, End:6}, minfys.Interval{Start:31, End:32}, minfys.Interval{Start:11, End:14}, minfys.Interval{Start:19, End:19}}'
Actual: 'minfys.Intervals{minfys.Interval{Start:5, End:6}, minfys.Interval{Start:11, End:14}, minfys.Interval{Start:19, End:19}, minfys.Interval{Start:31, End:32}}'
(Should resemble)!
* interval_test.go
Line 413:
Expected: 'minfys.Intervals{minfys.Interval{Start:7, End:10}, minfys.Interval{Start:1, End:3}, minfys.Interval{Start:15, End:17}}'
Actual: 'minfys.Intervals{minfys.Interval{Start:1, End:3}, minfys.Interval{Start:7, End:10}, minfys.Interval{Start:15, End:17}}'
(Should resemble)!
195 total assertions
...
198 total assertions
--- FAIL: TestIntervals (0.04s)
FAIL
.
$ diff -a -u ../interval_test.go interval_test.go
--- ../interval_test.go 2017-04-29 20:23:29.365344008 -0400
+++ interval_test.go 2017-04-29 20:54:14.349344903 -0400
@@ -244,19 +244,19 @@
So(len(ivs), ShouldEqual, 1)
newIvs = ivs.Difference(twoSix)
- So(newIvs, ShouldBeNil)
+ So(newIvs, ShouldBeEmpty)
ivs = ivs.Merge(twoSix)
So(len(ivs), ShouldEqual, 1)
newIvs = ivs.Difference(oneThree)
- So(newIvs, ShouldBeNil)
+ So(newIvs, ShouldBeEmpty)
ivs = ivs.Merge(oneThree)
So(len(ivs), ShouldEqual, 1)
oneSeven := Interval{1, 7}
newIvs = ivs.Difference(oneSix)
- So(newIvs, ShouldBeNil)
+ So(newIvs, ShouldBeEmpty)
ivs = ivs.Merge(oneSix)
So(len(ivs), ShouldEqual, 1)
@@ -372,7 +372,7 @@
fiveThirtyTwo := Interval{5, 32}
newIvs = ivs.Difference(fiveThirtyTwo)
- So(newIvs, ShouldResemble, Intervals{Interval{5, 6}, Interval{31, 32}, Interval{11, 14}, Interval{19, 19}})
+ So(newIvs, ShouldResemble, Intervals{Interval{5, 6}, Interval{11, 14}, Interval{19, 19}, Interval{31, 32}})
ivs = ivs.Merge(fiveThirtyTwo)
So(len(ivs), ShouldEqual, 3)
@@ -409,7 +409,7 @@
ivs = ivs.Truncate(17)
- expected := Intervals{sevenTen, oneThree, Interval{15, 17}}
+ expected := Intervals{oneThree, sevenTen, Interval{15, 17}}
So(ivs, ShouldResemble, expected)
})
})
.
$ go test
.............................................................................................................................................................................................................
205 total assertions
...
208 total assertions
PASS
$
我[@sbs]确认它比我的解决方案快。尽管如果你只是测量使用差异()所花费的墙时间(在interval_test.go中最后一个差异()调用之前加上一个:=时间。Now()在它之后,并在循环中求和这些持续时间),它似乎没有什么惊人的差异(在我的机器上,我的解决方案需要大约31毫秒,你的解决方案需要大约29毫秒)。
根据要求,进行间隔测试。go修改为测量墙壁时间:
$ diff -a -u ../interval_test.go walltime_test.go
--- ../interval_test.go 2017-04-29 20:23:29.365344008 -0400
+++ walltime_test.go 2017-04-30 13:39:29.000000000 -0400
@@ -24,6 +24,7 @@
"math/rand"
"testing"
"time"
+ "fmt"
)
func TestIntervals(t *testing.T) {
@@ -459,16 +460,20 @@
var ivs Intervals
errors := 0
+ var diffTime time.Duration
t := time.Now()
for i, input := range inputs {
iv := NewInterval(int64(input), int64(readSize))
+ before := time.Now()
newIvs := ivs.Difference(iv)
+ diffTime += time.Since(before)
if (len(newIvs) == 1) != exepectedNew[i] {
errors++
}
ivs = ivs.Merge(iv)
}
- // fmt.Printf("\ntook %s\n", time.Since(t))
+ fmt.Printf("took %s\n", time.Since(t))
+ fmt.Printf("\n Difference took %s\n", diffTime)
So(errors, ShouldEqual, 0)
So(len(ivs), ShouldEqual, 1)
So(time.Since(t).Seconds(), ShouldBeLessThan, 1) // 42ms on my machine
$
间隔测试。go基准输入大小和频率
size frequency
0 1
1 94929
2 50072
3 4998
输出大小和频率为
size frequency
0 50000
1 100000
调整peterSo对此分布的差分方法
package minfys
func (a Intervals) Difference(b Interval) Intervals {
// If A and B are sets, then the relative complement of A in B
// is the set of elements in B but not in A.
// The relative complement of A in B is denoted B ∖ A:
// B \ A = {x ∈ A | x ∉ B}
// B \ A = B ∩ A'
//
// For example. d = a\b,
// a: [{10, 15}, {30, 35}, {20, 25}]
// b: {5,32}
// d: [{5,9}, {16,19}, {26,29}]
// The elements of set a are non-overlapping, non-adjacent,
// and unsorted intervals.
if len(a) <= 0 {
return Intervals{b}
}
var d Intervals
for ; len(a) > 0; a = a[1:] {
for i := 1; i < len(a); i++ {
if a[i].Start < a[0].Start {
a[i], a[0] = a[0], a[i]
}
}
if b.Start < a[0].Start {
if b.End < a[0].Start {
d = append(d, b)
break
}
d = append(d, Interval{b.Start, a[0].Start - 1})
b.Start = a[0].Start
}
if b.End <= a[0].End {
break
}
if b.Start <= a[0].End {
b.Start = a[0].End + 1
}
if len(a) == 1 {
if b.Start <= a[0].End {
b.Start = a[0].End + 1
}
d = append(d, b)
break
}
}
return d
}
运行间隔测试。peterSO和sbs的差分方法的基准测试
$ go test -v
Merging many intervals is fast took 26.208614ms
Difference took 10.706858ms
和
$ go test -v
Merging many intervals is fast took 30.799216ms
Difference took 14.414488ms
PeterSO的差异方法明显快于sbs的:10.706858ms对14.414488ms或负25.7%。
更新peterSO修正差分法的早期示例基准结果
old.txt (sbs) versus new.txt (peterSO):
benchmark old ns/op new ns/op delta
BenchmarkExample-4 365 221 -39.45%
benchmark old allocs new allocs delta
BenchmarkExample-4 4 3 -25.00%
benchmark old bytes new bytes delta
BenchmarkExample-4 128 112 -12.50%
时间间隔:一条链上相邻区块的时间差。时间间隔越小,出块速度越快,TPS就越高。 本系统中,时间最小单位为1毫秒。 第一条链的时间间隔为1分钟,新链的时间间隔降为其父链的15/16,所以第二条链的时间间隔为56250毫秒。 新链有更小的时间间隔,出块速度更快。 区块的时间间隔可以根据需要调整,最大为1分钟。
间隔有开始和结束时间。间隔可能重叠。可能有几个包含时间t的间隔。只返回其中一个就可以了。 这是一个面试问题。我能够解决这个问题,方法是根据结束对间隔进行排序,根据开始对另一个时间进行排序,并取具有匹配开始和结束的间隔的交点。显然有更多优化的解决方案。 这里有一个例子:[1,5][2,10][3,6][2,9],目标是8。在这种情况下,[2,10]和[2,9]中的任何一个都是正确答案。 我想问题的关
问题内容: 我需要将表分组为15分钟间隔。我可以这样做: 但是要在图表中显示返回的数据,我还需要插入没有任何数据且当前未出现在我的select语句中的间隔。我该如何插入这些? 问题答案: 用15分钟的增量创建一个带有所有可能时间戳的表,然后从该表向上面的查询进行LEFT JOIN。 如果您知道图表始终涵盖24小时,则只需创建一个数字为0-95的表格,然后为每个条目将其添加到图表的开始时间。
# interval(date) Alias for interval.floor(date). For example, d3.time.day(new Date()) returns midnight (12:00 AM) on the current day, in local time. # interval.floor(date) Rounds down the specified da
让事件反复发生 用法 Your browser does not support the video tag. 案例:坏掉的小台灯 功能:不停闪烁 工作原理 在配置项中可以选择每隔多少秒反转一次 例:制作一个闪烁的灯 例:温度过高时会发出“哔哔”声报警
假设我有一个这样的范围列表 现在我想找到一个范围,比如。我的算法应该给我这个范围的所有范围。例如,这个的输出应该是 <代码>输出-[1,3]、[2,5]、[4,6]、[8,10] 我该如何着手解决这个问题? PS:我知道段树可能会有所帮助。我可以在其中构建树来存储间隔并查询位于间隔内的Point,但如何在给定间隔的情况下获取所有间隔。