In [1]:
import (
"fmt"
"math/rand"
"sort"
)
In [2]:
// Return leftmost offset where val can be inserted in sl while
// maintaining sorted orter. Assumes sl is sorted.
func bisectLeftInt(sl []int, val int) int {
return sort.Search(len(sl), func(i int) bool {return sl[i] >= val})
}
In [3]:
// Same but for rightmost offset
func bisectRightInt(sl []int, val int) int {
return sort.Search(len(sl), func(i int) bool {return sl[i] > val})
}
In [4]:
// Same as bisectLeftInt but where val and sl contain strings
func bisectLeftStr(sl []string, val string) int {
return sort.Search(len(sl), func(i int) bool {return sl[i] >= val})
}
In [5]:
// Same but for rightmost offset
func bisectRightStr(sl []string, val string) int {
return sort.Search(len(sl), func(i int) bool {return sl[i] > val})
}
In [6]:
a := []int{1, 2, 3, 3, 3, 4, 5}
bisectLeftInt(a, 3)
In [7]:
bisectRightInt(a, 3)
In [8]:
a = []int{2, 4, 6, 8, 10}
bisectLeftInt(a, 5)
In [9]:
bisectRightInt(a, 5)
In [10]:
// Make a list of pseudo-random integers in [1, 99]
rand.Seed(77)
ls := make([]int, 30)
for i := range ls {
ls[i] = rand.Intn(100) + 1
}
ls
In [11]:
sort.Ints(ls)
ls
In [12]:
// The number 30 is not in the sorted list
// If it were, where would it go?
val := 30
insPt := bisectLeftInt(ls, val)
insPt
In [13]:
// Insert it
ls = append(ls, 0)
copy(ls[insPt+1:], ls[insPt:])
ls[insPt] = val
ls
In [14]:
// 62 appears multiple times
st := bisectLeftInt(ls, 62)
en := bisectRightInt(ls, 62)
st
In [15]:
en
In [16]:
ls[st:en]
In [17]:
// Of course, there also exists a total ordering over strings
// (lexicographical ordering), so we can do all the same things
// with strings
strls := []string{"a", "awkward", "awl", "awls", "axe", "axes", "bee"}
st = bisectLeftStr(strls, "awl")
en = bisectRightStr(strls, "awl")
st
In [18]:
en
In [19]:
// Say we want to get the range of elements that have some prefix,
// e.g. 'aw' and say that 'z' is the lexicographically greatest
// character in the alphabet.
st, en = bisectLeftStr(strls, "aw"), bisectLeftStr(strls, "ax")
st
In [20]:
en
In [21]:
strls[st:en]
In [22]:
// If we can do this for any sorted list of strings, we can do it for
// a sorted list of suffixes
t := "abaaba$"
suffixes := []string{t, t[1:], t[2:], t[3:], t[4:], t[5:], t[6:]}
sort.Strings(suffixes)
suffixes
In [23]:
// Search for suffixes starting with aba
st = bisectLeftStr(suffixes, "aba")
en = bisectLeftStr(suffixes, "abb")
st
In [24]:
en