Set
We can keep a set of the actual numbers contained within ranges.
class RangeModule:
def __init__(self):
self.range_set = set()
def addRange(self, left: int, right: int) -> None:
for x in range(left, right):
self.range_set.add(x)
def queryRange(self, left: int, right: int) -> bool:
for x in range(left, right):
if x not in self.range_set:
return False
return True
def removeRange(self, left: int, right: int) -> None:
for x in range(left, right):
self.range_set.discard(x)
# Your RangeModule object will be instantiated and called as such:
# obj = RangeModule()
# obj.addRange(left,right)
# param_2 = obj.queryRange(left,right)
# obj.removeRange(left,right)
Sorted list of ranges
We maintain a list of disjoint ranges sorted by left.
Say at the time of operations, there are disjoint ranges. Total space is
.
| Operation | Time | Space |
__init__ | ||
addRange | ||
queryRange | ||
removeRange |
class RangeModule:
def __init__(self):
self.ranges = []
def __merge(self):
if not self.ranges:
return
self.ranges.sort()
merged = []
prev = self.ranges[0]
for i in range(1, len(self.ranges)):
curr = self.ranges[i]
if prev[1] < curr[0]:
merged.append(prev)
prev = curr
else:
prev = [ prev[0], max(prev[1], curr[1]) ]
merged.append(prev)
self.ranges = merged
def addRange(self, left: int, right: int) -> None:
self.ranges.append( [left, right] )
self.__merge()
def queryRange(self, left: int, right: int) -> bool:
for r in self.ranges:
if left >= r[0] and right <= r[1]:
return True
return False
def removeRange(self, left: int, right: int) -> None:
removed = []
for r in self.ranges:
if r[1] <= left or r[0] >= right:
removed.append(r)
else: # overlaps
left_range = [ r[0], left ]
if left_range[0] < left_range[1]:
removed.append(left_range)
right_range = [ right, r[1] ]
if right_range[0] < right_range[1]:
removed.append( right_range )
self.ranges = removed
# Your RangeModule object will be instantiated and called as such:
# obj = RangeModule()
# obj.addRange(left,right)
# param_2 = obj.queryRange(left,right)
# obj.removeRange(left,right)
Since we have a sorted list of disjoint ranges, we can do binary-search in queryRange().
| Operation | Time | Space |
__init__ | ||
addRange | ||
queryRange | ||
removeRange |
class RangeModule:
def __init__(self):
self.ranges = []
def __merge(self):
if not self.ranges:
return
self.ranges.sort()
merged = []
prev = self.ranges[0]
for i in range(1, len(self.ranges)):
curr = self.ranges[i]
if prev[1] < curr[0]:
merged.append(prev)
prev = curr
else:
prev = [ prev[0], max(prev[1], curr[1]) ]
merged.append(prev)
self.ranges = merged
def addRange(self, left: int, right: int) -> None:
self.ranges.append( [left, right] )
self.__merge()
def queryRange(self, left: int, right: int) -> bool:
lo, hi = 0, len(self.ranges)-1
while lo <= hi:
mid = (lo + hi) // 2
if self.ranges[mid][1] <= left:
lo = mid+1
else:
hi = mid-1
if lo == len(self.ranges):
return False
container_left, container_right = self.ranges[lo]
return container_left <= left and right <= container_right
def removeRange(self, left: int, right: int) -> None:
removed = []
for r in self.ranges:
if r[1] <= left or r[0] >= right:
removed.append(r)
else: # overlaps
left_range = [ r[0], left ]
if left_range[0] < left_range[1]:
removed.append(left_range)
right_range = [ right, r[1] ]
if right_range[0] < right_range[1]:
removed.append( right_range )
self.ranges = removed
# Your RangeModule object will be instantiated and called as such:
# obj = RangeModule()
# obj.addRange(left,right)
# param_2 = obj.queryRange(left,right)
# obj.removeRange(left,right)
Since we already have the ranges sorted, we do not need to sort in addRange().
| Operation | Time | Space |
__init__ | ||
addRange | ||
queryRange | ||
removeRange |
class RangeModule:
def __init__(self):
self.ranges = []
def addRange(self, left: int, right: int) -> None:
if not self.ranges:
self.ranges.append([left, right])
return
merged = []
i = 0
while i < len(self.ranges) and self.ranges[i][1] < left:
merged.append(self.ranges[i])
i += 1
if i == len(self.ranges):
self.ranges.append([left, right])
return
if left < self.ranges[i][0]:
prev = [left, right]
else:
prev = [ self.ranges[i][0], max(right, self.ranges[i][1]) ]
i += 1
while i < len(self.ranges):
curr = self.ranges[i]
if prev[1] < curr[0]:
merged.append(prev)
prev = curr
else:
prev = [ prev[0], max( prev[1], curr[1] ) ]
i += 1
merged.append(prev)
self.ranges = merged
def queryRange(self, left: int, right: int) -> bool:
lo, hi = 0, len(self.ranges)-1
while lo <= hi:
mid = (lo + hi) // 2
if self.ranges[mid][1] <= left:
lo = mid+1
else:
hi = mid-1
if lo == len(self.ranges):
return False
container_left, container_right = self.ranges[lo]
return container_left <= left and right <= container_right
def removeRange(self, left: int, right: int) -> None:
removed = []
for r in self.ranges:
if r[1] <= left or r[0] >= right:
removed.append(r)
else: # overlaps
left_range = [ r[0], left ]
if left_range[0] < left_range[1]:
removed.append(left_range)
right_range = [ right, r[1] ]
if right_range[0] < right_range[1]:
removed.append( right_range )
self.ranges = removed
# Your RangeModule object will be instantiated and called as such:
# obj = RangeModule()
# obj.addRange(left,right)
# param_2 = obj.queryRange(left,right)
# obj.removeRange(left,right)
Leave a comment