题目:
假设你正在读取一串整数。每隔一段时间,你希望能找出数字 x 的秩(小于或等于 x 的值的个数)。请实现数据结构和算法来支持这些操作,也就是说:
实现 track(int x) 方法,每读入一个数字都会调用该方法;
实现 getRankOfNumber(int x) 方法,返回小于或等于 x 的值的个数。
算法:
方法一:树状数组
因为数组index的限制,实际上要求限制数据范围[0,5000],否则需要将track的数字进行离散化。
type StreamRank struct {
BIT []int
}
func Constructor() StreamRank {
return StreamRank{make([]int,50002)}
}
func (this *StreamRank) Track(i int) {
i ++
for i < len(this.BIT) {
this.BIT[i] = this.BIT[i] + 1
i = i + lowBit(i)
}
}
func (this *StreamRank) GetRankOfNumber(i int) int {
ans := 0
i ++
for i > 0 {
ans = ans + this.BIT[i]
i = i - lowBit(i)
}
return ans
}
func lowBit(x int) int {
return x & (-x)
}
方法二:插入+二分查找
小知识点get,如何在slice的中间插入元素。利用copy的性质,不创建临时数组,将内存使用率降到更低:
利用append,创建临时数组:
利用copy,不创建临时数组:
type StreamRank struct {
BIT []int
}
func Constructor() StreamRank {
return StreamRank{make([]int,0)}
}
func (this *StreamRank) Track(i int) {
index := this.GetRankOfNumber(i)
// 方法一 创建临时切片
// this.BIT = append(this.BIT[:index], append([]int{i}, this.BIT[index:]...)...)
// 方法二 不创建临时切片
this.BIT = append(this.BIT, 0)
copy(this.BIT[index + 1:], this.BIT[index:])
this.BIT[index] = i
}
// 小于等于i的元素个数
func (this *StreamRank) GetRankOfNumber(i int) int {
left, right := 0, len(this.BIT) - 1
i = i + 1
// 找到小于i+1的元素个数
for left <= right {
// fmt.Println(left, right)
mid := (left + right) / 2
if this.BIT[mid] < i{
left = mid + 1
} else if this.BIT[mid] > i{
right = mid - 1
} else {
if mid > 0 && this.BIT[mid - 1] == i {
right = mid - 1
} else {
return mid
}
}
}
return left
}
方法三:方法二二分的另一种写法
type StreamRank struct {
BIT []int
}
func Constructor() StreamRank {
return StreamRank{make([]int,0)}
}
func (this *StreamRank) Track(i int) {
index := this.GetRankOfNumber(i)
// 方法一 创建临时切片
// this.BIT = append(this.BIT[:index], append([]int{i}, this.BIT[index:]...)...)
// 方法二 不创建临时切片
this.BIT = append(this.BIT, 0)
copy(this.BIT[index + 1:], this.BIT[index:])
this.BIT[index] = i
}
// 小于等于i的元素个数
func (this *StreamRank) GetRankOfNumber(i int) int {
left, right := 0, len(this.BIT) -
// 二分方法二
for left <= right {
mid := (left + right) / 2
if this.BIT[mid] <= i{
left = mid + 1
} else {
right = mid - 1
}
}
return left
}