Imagine you are reading in a stream of integers. Periodically, you wish to be able to look up the rank of a number x (the number of values less than or equal to x). lmplement the data structures and algorithms to support these operations. That is, implement the method track (int x), which is called when each number is generated, and the method getRankOfNumber(int x), which returns the number of values less than or equal to x.
Note: This problem is slightly different from the original one in the book.
The number of calls of both track and getRankOfNumber methods are less than or equal to 2000.
Solutions
Solution 1: Binary Indexed Tree
We can use a Binary Indexed Tree (also known as a Fenwick Tree) to maintain the count of numbers that are less than or equal to the current number among the added numbers.
We create a Binary Indexed Tree with a length of $50010$. For the track method, we increment the current number and add it to the Binary Indexed Tree. For the getRankOfNumber method, we directly query the count of numbers that are less than or equal to $x + 1$ in the Binary Indexed Tree.
In terms of time complexity, both the update and query operations of the Binary Indexed Tree have a time complexity of $O(\log n)$, where $n$ is the length of the Binary Indexed Tree.
classBinaryIndexedTree:__slots__="n","c"def__init__(self,n:int):self.n=nself.c=[0]*(n+1)defupdate(self,x:int,delta:int)->None:whilex<=self.n:self.c[x]+=deltax+=x&-xdefquery(self,x:int)->int:s=0whilex:s+=self.c[x]x-=x&-xreturnsclassStreamRank:def__init__(self):self.tree=BinaryIndexedTree(50010)deftrack(self,x:int)->None:self.tree.update(x+1,1)defgetRankOfNumber(self,x:int)->int:returnself.tree.query(x+1)# Your StreamRank object will be instantiated and called as such:# obj = StreamRank()# obj.track(x)# param_2 = obj.getRankOfNumber(x)
classBinaryIndexedTree{privateintn;privateint[]c;publicBinaryIndexedTree(intn){this.n=n;this.c=newint[n+1];}publicvoidupdate(intx,intdelta){for(;x<=n;x+=x&-x){c[x]+=delta;}}publicintquery(intx){ints=0;for(;x>0;x-=x&-x){s+=c[x];}returns;}}classStreamRank{privateBinaryIndexedTreetree=newBinaryIndexedTree(50010);publicStreamRank(){}publicvoidtrack(intx){tree.update(x+1,1);}publicintgetRankOfNumber(intx){returntree.query(x+1);}}/** * Your StreamRank object will be instantiated and called as such: * StreamRank obj = new StreamRank(); * obj.track(x); * int param_2 = obj.getRankOfNumber(x); */
classBinaryIndexedTree{private:intn;vector<int>c;public:BinaryIndexedTree(intn):n(n),c(n+1){}voidupdate(intx,intdelta){for(;x<=n;x+=x&-x){c[x]+=delta;}}intquery(intx){ints=0;for(;x>0;x-=x&-x){s+=c[x];}returns;}};classStreamRank{public:StreamRank(){}voidtrack(intx){tree->update(x+1,1);}intgetRankOfNumber(intx){returntree->query(x+1);}private:BinaryIndexedTree*tree=newBinaryIndexedTree(50010);};/** * Your StreamRank object will be instantiated and called as such: * StreamRank* obj = new StreamRank(); * obj->track(x); * int param_2 = obj->getRankOfNumber(x); */
typeBinaryIndexedTreestruct{nintc[]int}funcNewBinaryIndexedTree(nint)*BinaryIndexedTree{return&BinaryIndexedTree{n:n,c:make([]int,n+1)}}func(bit*BinaryIndexedTree)update(x,deltaint){for;x<=bit.n;x+=x&-x{bit.c[x]+=delta}}func(bit*BinaryIndexedTree)query(xint)int{s:=0for;x>0;x-=x&-x{s+=bit.c[x]}returns}typeStreamRankstruct{tree*BinaryIndexedTree}funcConstructor()StreamRank{returnStreamRank{NewBinaryIndexedTree(50010)}}func(this*StreamRank)Track(xint){this.tree.update(x+1,1)}func(this*StreamRank)GetRankOfNumber(xint)int{returnthis.tree.query(x+1)}/** * Your StreamRank object will be instantiated and called as such: * obj := Constructor(); * obj.Track(x); * param_2 := obj.GetRankOfNumber(x); */
classBinaryIndexedTree{privaten:number;privatec:number[];constructor(n:number){this.n=n;this.c=Array(n+1).fill(0);}update(x:number,delta:number):void{for(;x<=this.n;x+=x&-x){this.c[x]+=delta;}}query(x:number):number{lets=0;for(;x>0;x-=x&-x){s+=this.c[x];}returns;}}classStreamRank{privatetree:BinaryIndexedTree=newBinaryIndexedTree(50010);constructor(){}track(x:number):void{this.tree.update(x+1,1);}getRankOfNumber(x:number):number{returnthis.tree.query(x+1);}}/** * Your StreamRank object will be instantiated and called as such: * var obj = new StreamRank() * obj.track(x) * var param_2 = obj.getRankOfNumber(x) */