没事刷刷题——包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

题目不难,关键需要一个辅助内存去维护当前栈中的最小元素。第一感觉,就是用用一个multiset去维护最小值列表,不用set的原因是无法插入两个相同的值,但是,测试发现结果不对。错误的第一版代码如下:

class Solution {
public:
    void push(int value) {
        m_stack.push_back(value);
        m_orderSet.insert(value);
    }
    void pop() {
        if (m_stack.empty())
            return;
        
        m_orderSet.erase(this->top());
        m_stack.erase((m_stack.end() - 1));
    }
    int top() {
        return m_stack.empty() ? 0 : *(m_stack.rbegin());
    }
    int min() {
        return m_orderSet.empty() ? 0 : *(m_orderSet.begin());
    }
    
    std::vector m_stack;
    std::multiset m_orderSet;
};

一脸懵逼,觉得逻辑没人任何毛病,为啥死活通不过去??最后debug下来,发现问题出现在m_orderSet.erase(this->top())上面,哎,竟然一直没注意到multiset的erase如果传值的话,是会把set内等于该数值的全部元素都会删除掉的。。。
跑去看了下STLPort源码验证下。
set和multiset底层都是红黑树,看RBTree的erase实现:

size_type erase(const key_type& __x) {
    pair __p = equal_range(__x);
    size_type __n = _STLP_STD::distance(__p.first, __p.second);
    erase(__p.first, __p.second);
    return __n;
  }

pair equal_range(const _KT& __x)
{ return pair(lower_bound(__x), upper_bound(__x)); }

源码清晰可见,RBTree在erase时会先调用equal_range去查找等于这个值的所有元素,并返回这个区间,然后全部删除,最后erase函数会返回这个区间的距离(也就是实际删除的元素个数)。

知道了问题,就好办了,修改pop()部分代码,换成传入迭代器的方式调用erase即可。

for (auto it = m_orderSet.begin(); it != m_orderSet.end(); ++it)
{
     if (*it == this->top())
     {
         m_orderSet.erase(it);
         break;
     }
 }

修改完,提交,测试通过。
最后,再记录分享下另一种实现,采用另一个辅助栈去实现,两个栈,一个用于实际的逻辑栈A,另一个栈B维护当前最小值。
具体操作流程:每push一个元素X到A时,判断下X是否小于B的栈顶元素,如果满足,同时push x到B中,否则,push B的栈顶元素到B中;每次pop时,A、B栈同时pop。
例如 push A: 3, 4, 2, 5, 1; B: 3, 3, 2, 2, 1。

你可能感兴趣的:(#,C++,算法和数据结构)