for i inrange(1, n+1): iflen(self.buckets[-1]) == bucket_size: self.buckets.append(deque()) self.buckets[-1].append(i)
deffetch(self, k: int) -> int: for idx, bucket inenumerate(self.buckets): # this speed up the look up process if k > len(bucket): k -= len(bucket) else: break # move element to the tail self.buckets[-1].append(bucket[k-1])
# update bucket, since we removed bucket[k-1] new_bucket = deque() for i , e inenumerate(bucket, 1): if i != k: new_bucket.append(e) self.buckets[idx] = new_bucket
# re-balancing for i inrange(idx, len(self.buckets)-1): self.buckets[i].append(self.buckets[i+1].popleft())
return self.buckets[-1][-1]
runtime: 455ms
memory: 15.2MB
solution 4 - sqrt decomposition
similiar with above, but use a little bit match to speed up
def__init__(self, n: int): bucket_size = math.ceil(sqrt(n)) self.buckets = [] # record the first index of number for each bucket, for ex, bucket 1 start from 1, bucekt 2 start from # bucket_size +1, bucket 3 start from 2*bucket_size + 1, etc self.index = []
for i inrange(1, n+1): ii = (i-1)//bucket_size # 1 -> bucket_size would go to bucket 1 # bucket_size -> 2*bucket_size would go to bucket 2 , etc if ii == len(self.buckets): self.buckets.append([]) self.index.append(i) self.buckets[-1].append(i)
deffetch(self, k: int) -> int: # binary search, quickly locate the bucket for k idx = bisect_right(self.index, k)-1 # pop the element at index k self.buckets[-1].append(self.buckets[idx].pop(k - self.index[idx]))
# re-balancing, need to guarantee each has size sqrt(n) for i inrange(idx, len(self.buckets)-1): self.buckets[i].append(self.buckets[i+1].pop(0)) return self.buckets[-1][-1]
defsum(self, k: int): res = 0 # notice the bit start from index 1 k += 1 while k: res += self.nums[k] k -= self._lowbit(k) return res
defadd(self, k: int, x: int): # notice the bit start from index 1 k += 1 while k < len(self.nums): self.nums[k] += x k += self._lowbit(k)
def_lowbit(self, x: int): return x & (-x)
classMRUQueue: def__init__(self, n: int): # total query <= 2000 # At most 2000 calls will be made to fetch. self.bit = BIT(n + 2000) self.size = n self.vals = [0] * (n + 2000)
# time complexity O(NlogN) for i inrange(n): # bit record how many elements are there at index i # time complexity O(logN) self.bit.add(i, 1) # self.vals , index -> element value mapping self.vals[i] = i + 1
deffetch(self, k: int) -> int: lo, high = 0, self.size # binary seach on bit tree, find index mid so from [0,mid] which exactly has k element # time complexity: O(lgN * lgN) = O((lgN)^2) while lo < high: mid = (lo + high) >> 1 # time complexity: O(logN) if self.bit.sum(mid) < k: lo = mid + 1 else: high = mid # add kth element to the tail self.vals[self.size] = self.vals[lo] # since kth element moved to tail, so at postion lo we need to deduct 1 element self.bit.add(lo, -1) # since tail has extra element, we need to record it on bit tree self.bit.add(self.size, 1) # since we append elment to tail, the size need to increment self.size += 1