Reputation: 971
I need to design a data structure that supports the following:
getMinElement
, getLastElement
, insertElement
, deleteLastElement
- in O(1)
run time.
Memory is bounded by n (not O(n)) i.e. You can keep at most n elements at a given moment. plus O(1) memory.
(Important: pointers are regarded as 1 as well, so linked list, for instance, is out of the question).
Example:
insert(6)
min() -> 6
insert(10)
insert(5)
min() -> 5
insert(7)
delete()
min() -> 5
delete()
min() -> 6
Upvotes: 1
Views: 246
Reputation: 386018
We'll store the most recent minimum directly. This is O(1) space.
We'll also use an array of integers, since that seems to be our only option for variable-length space. But we won't store the elements directly. Instead, when we insert an element, we'll store the difference between that element and the (prior) minimum. When we delete an element, we can use that difference to restore the prior minimum if necessary.
In Python:
class MinStorage:
def __init__(self):
self.offsets = []
self.min = None
def insertElement(self, element):
offset = 0 if self.min is None else (element - self.min)
self.offsets.append(offset)
if self.min is None or offset < 0:
self.min = element
def getMinElement(self):
return self.min
def getLastElement(self):
offset = self.offsets[-1]
if offset < 0:
# Last element defined a new minimum, so offset is an offset
# from the prior minimum, not an offset from self.min.
return self.min
else:
return self.min + offset
def deleteLastElement(self):
offset = self.offsets[-1]
self.offsets.pop()
if len(self.offsets) == 0:
self.min = None
if offset < 0:
self.min -= offset
Here's a version that allows any unsigned 16-bit integer as an element, and only stores unsigned 16-bit integers in the array:
class MinStorage:
Cap = 65536
def __init__(self):
self.offsets = []
self.min = None
def insertElement(self, element):
assert 0 <= element < self.Cap
offset = 0 if self.min is None else (element - self.min)
if offset < 0: offset += self.Cap
self.offsets.append(offset)
if self.min is None or element < self.min:
self.min = element
def getMinElement(self):
return self.min
def getLastElement(self):
element = self.__getLastElementUnchecked()
if element < self.min:
# Last element defined a new minimum, so offset is an offset
# from the prior minimum, not an offset from self.min.
return self.min
else:
return element
def deleteLastElement(self):
element = self.__getLastElementUnchecked()
self.offsets.pop()
if len(self.offsets) == 0:
self.min = None
elif element < self.min:
# Popped element defined a new minimum.
self.min = element
def __getLastElementUnchecked(self):
offset = self.offsets[-1]
element = self.min + offset
if element >= self.Cap:
element -= self.Cap
return element
Note that in a language with unsigned 16-bit arithmetic that wraps on overflow/underflow, you wouldn't need the checks and adjustments involving self.Cap
. In C (§6.2.5/9) and C++ (§3.9.1/4), unsigned arithmetic is required to behave as needed. However, Python doesn't support unsigned 16-bit arithmetic.
Upvotes: 5
Reputation: 2074
If you can assume something like "data is in the range 0 to 255 (int8)", and you are allowed to store an integer of twice the precision (int16), then you could store the "cumulative minimum" in the upper byte and the data point in the lower byte. Other than something like this, I don't believe this is possible within the constraints you have given.
Upvotes: 0
Reputation: 881
Use a stack that stores both the inserted value and the current min. The current min is updated when inserting (push) a value, by comparing the value against the current min, and when deleting (pop) a value peeking the current min value from the top of the stack.
Upvotes: 1