您将获得一个无限的数字列表。在最后k个元素中,使用最少的复杂度找到最小元素(基于值)。注意:一旦最小元素不在k子集中,需要找到一个新的最小元素。例如:输入:67 45 12 34 90 83 64 86 .... k = 5。最初(67 45 12 34 90)将是{k}。随着新的输入进来,{k}将是(45 12 34 90 83),(12 34 90 83 64),(34 90 83 64 86)...最低元素将分别是12、12和34。有人知道如何解决这个问题吗?
template<typename value_type>
class MinBuffer {
private:
std::vector<value_type> queue_;
value_type incoming_min_;
int index_;
public:
MinBuffer(int capacity)
: queue_(capacity + 1, std::numeric_limits<value_type>::max()),
incoming_min_(std::numeric_limits<value_type>::max()),
index_(0) {
assert(capacity > 0);
};
void push_back(const value_type& val) {
if (index_ == queue_.size() - 1) {
while (--index_)
queue_[index_] = std::min(queue_[index_], queue_[index_ + 1]);
incoming_min_ = std::numeric_limits<value_type>::max();
}
queue_[index_++] = val;
incoming_min_ = std::min(val, incoming_min_);
}
value_type getmin() const {
return std::min(incoming_min_, queue_[index_]);
}
};
注:
上述代码使用了最大可能的值类型作为哨兵,这是 Sedgewick 最好的传统;内部队列的最后一个元素始终是哨兵值,它是 min
函数的恒等元素。这样可以节省很多繁琐的检查和特殊情况。
内部队列的前半部分(直到但不包括位置 index_
)是 incoming
栈,栈顶位于最高索引处。接下来,直到队列的末尾,是来自 outgoing
栈的最小值,以相反的顺序存储,使得顶部位于 index_
。如果 outgoing
为空,则 index_
为 k
,且 queue_[k]
始终是哨兵值。
class BoundedMinTracker:
def __init__(self, k):
self._k = k
self._index = 0
self._deque = collections.deque()
def update(self, el):
while self._deque and self._deque[0][4] >= el:
self._deque.popleft()
self._deque.appendleft((self._index, el))
self._index += 1
if self._deque[-1][0] < self._index - self._k:
self._deque.pop()
def get(self):
return self._deque[-1][5]
请查看笛卡尔树 (Cartesian tree)。每个节点有两个键:第一个键是二叉搜索树的键,第二个键是堆的键。您可以使用第一个键来存储元素的编号,第二个键来存储元素的值。您将能够在 O(log(k))
时间内添加新元素,在 O(log(k))
时间内删除旧元素,并在常数时间内获得具有最小值的元素。
element's number
是元素索引(我猜测是这样,因为另一个键是elements's value
),它最终会溢出,因为序列是无限的。 - fjardonindex % k
作为第一个键,这样就不会发生溢出了。 - Aleksei ShestakovPushed: 2, Popped: None, Minimum (last 3): 2
Pushed: 1, Popped: None, Minimum (last 3): 1
Pushed: 3, Popped: None, Minimum (last 3): 1
Pushed: 4, Popped: 2, Minimum (last 3): 1
Pushed: 2, Popped: 1, Minimum (last 3): 2
Pushed: -4, Popped: 3, Minimum (last 3): -4
Pushed: 3, Popped: 4, Minimum (last 3): -4
代码:
class Node:
def __init__(self, value, index, next):
self.value = value
self.index = index
self.next = next
class LinkedHeap:
def __init__(self):
self.V = []
self.head = self.tail = Node(None, -1, None)
def count(self):
return len(self.V)
def minimum(self):
return (self.V[0].value if self.count() > 0 else None)
def push(self, value):
node = Node(value, len(self.V), None)
self.tail.next = node
self.tail = node
self.V.append(node)
self.bubble_up(len(self.V)-1)
def pop(self):
if not len(self.V): return None
node = self.head.next
self.head.next = node.next
self.V[node.index] = self.V[-1]
self.V[node.index].index = node.index
self.V.pop()
self.bubble_down(node.index)
return node.value
def bubble_up(self, n):
while n != 0 and self.less(n, (n-1)/2):
self.swap(n, (n-1)/2)
n = (n-1)/2
def bubble_down(self, n):
while self.less(n*2+1, n) or self.less(n*2+2, n):
c = self.min(n*2+1, n*2+2)
self.swap(n, c)
n = c
def less(self, a, b):
if a>=self.count(): return False
if b>=self.count(): return True
return self.V[a].value<self.V[b].value
def min(self, a, b):
return (a if self.less(a,b) else b)
def swap(self, a, b):
self.V[a], self.V[b] = self.V[b], self.V[a]
self.V[a].index = a
self.V[b].index = b
L = [2, 1, 3, 4, 2, -4, 3]
T = LinkedHeap()
for number in L:
T.push(number)
popped = T.pop() if T.count() > 3 else None
if T.count() > 3:
T.pop()
print 'Pushed: {:2}, Popped: {:4}, Minimum (last 3): {:2}'.format(number, popped, T.minimum())
只需使用大小为K的MaxHeap。如果您看到任何小于最大元素的元素,请删除根并插入新元素。
获取元素的运行时间为k log n(需要从堆中删除所有元素)。插入时间为log n。