面试问题:设计具有以下功能的数据结构
以上所有操作都应具有O(1)
答案 0 :(得分:13)
您可以通过维护两个堆栈
来完成此操作 stack
- 在此堆栈上执行常规的推送和弹出操作。
minStack
- 此堆栈用于在O(1)
时间内获取堆栈中的最小元素。在任何时候,该堆栈的顶部元素将是堆栈中所有元素的最小值。
push( item a)
// push the element on the stack.
stack.push(a)
// find the min of the ele to be pushed and the ele on top of minStack.
if(minStack.isEmpty())
min = a
else
min = Min(a,minStack.top())
// push the min ele on the minStack.
minStack.push(min)
end push
pop()
// pop and discard
minStack.pop()
// pop and return
return stack.pop()
end pop
findMin()
return minStack.top()
end findMin
在上面的解决方案中,每次在堆栈上推送元素时,都会在minStack
上进行相应的推送。因此,堆栈和minStack
中的元素数量在任何时候都是相同的。只有当元素小于当前最小值时,我们才能通过将元素推送到minStack
来稍微优化它。
push( item a)
// push the element on the orginal stack.
stack.push(a)
if(minStack.isEmpty())
// if minStack is empty push.
minStack.push(a)
// else push only if the element is less than or equal to the present min.
else if(a <= minStack.top())
minStack.push(a)
end push
pop()
// pop from the stack
ele = stack.top()
if(minStack.top() == ele)
// pop only if the top element is ele.
minStack.pop()
// return the popped element.
return ele
end pop
答案 1 :(得分:2)
为此,您的数据结构应包含两个堆栈。一个应该正常运作;另一个只包含最后看到的最小元素。当你按下一个元素时,如果它小于/等于第二个堆栈的顶部(或者堆栈是空的),也可以将它推到第二个堆栈上。弹出元素时,如果它等于第二个堆栈的顶部,则弹出第二个堆栈。
任何时候的最小值都是第二个堆栈的顶部。
答案 2 :(得分:1)
这个问题实际上是要求Heap
PriorityQueue是一个经典案例(Heap的实现)。见java.util.PriorityQueue
我希望在线提供一种简单的方法来引用Java语言源代码,我可以看到它并参考PriorityQueue类的实现。
答案 3 :(得分:0)
在不使用辅助堆栈的情况下,有一个更有创意的解决方案。
假设我们要将数字值推送到最小数量 min 的堆栈中。如果 value 大于或等于 min ,则会将其直接推送到数据堆栈中。如果它小于 min ,我们按2 **值* - min ,并将 min 更新为值因为推出了新的最小数量。
流行怎么样?如果数据堆栈的顶部(表示为 top )大于或等于 min ,我们会直接弹出它。否则,数字 top 不是真正推送的数字。实际推送的数字存储为 min 。在弹出当前最小数量后,我们需要恢复之前的最小数字,即2 ** min * - top 。
现在让我们展示一下这个解决方案的正确性。当值大于或等于 min 时,它将直接推送到数据堆栈而不更新 min 。因此,当我们发现数据堆栈的顶部大于或等于 min 时,我们可以直接弹出而不更新 min 。但是,如果我们发现 value 小于 min ,我们会推送2 值* - min 。我们应该注意到2 值* - min 小于值。然后我们将当前 min 更新为值。因此,新的数据堆栈顶部( top )小于当前的 min 。因此,当我们发现数据堆栈的顶部小于 min 时,真正的顶部(实际推送数值)存储在 min 中。在我们弹出数据堆栈的顶部之后,我们必须恢复之前的最小数量。由于 top = 2 **值* - 以前 min 和值是当前 min ,因此 min 是2 *当前 min - top 。
C ++示例代码如下所示:
template <typename T> class StackWithMin {
public:
StackWithMin(void) {}
virtual ~StackWithMin(void) {}
T& top(void);
void push(const T& value);
void pop(void);
const T& min(void) const;
private:
std::stack<T> m_data; // data stack, to store numbers
T m_min; // minimum number
};
template <typename T> void StackWithMin<T>::push(const T& value) {
if(m_data.size() == 0) {
m_data.push(value);
m_min = value;
}
else if(value >= m_min) {
m_data.push(value);
}
else {
m_data.push(2 * value - m_min);
m_min = value;
}
}
template <typename T> void StackWithMin<T>::pop() {
assert(m_data.size() > 0);
if(m_data.top() < m_min)
m_min = 2 * m_min - m_data.top();
m_data.pop();
}
template <typename T> const T& StackWithMin<T>::min() const {
assert(m_data.size() > 0);
return m_min;
}
template <typename T> T& StackWithMin<T>::top() {
T top = m_data.top();
if(top < m_min)
top = m_min;
return top;
}
此解决方案借鉴my blog和我的书“Coding Interviews: Questions, Analysis & Solutions”。