第30题:LeetCode155. Min Stack最小栈

设计一个支持 push,pop,top 操作,并能在O(1)时间内检索到最小元素的栈。

  • push(x) -- 将元素 x 推入栈中。
  • pop() -- 删除栈顶的元素。
  • top() -- 获取栈顶元素。
  • getMin() -- 检索栈中的最小元素。

示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

考点

1.举例模拟抽象规律

2.复杂问题简单化

3.辅助容器

4.stack


思路

1.每次压入数据栈时,如果minstack.empty() || minstack.top()>=input,两个一起入栈

2.每次数据栈弹出时,如果mintack.top()==datastack.top(),两个一起出栈,弹出后辅助栈top依然是数据栈中的最小元素。

保证辅助栈的top是最小元素,且辅助栈的元素是递减排列


代码

newcoder

class Solution {
public:
    stack<int> data;
    stack<int> mins;
    void push(int value) 
    {
        if(!mins.size()||mins.top()>=value)
            mins.push(value);
        
        data.push(value);
    }
    void pop() 
    {
        if(data.size() > 0 && mins.size() > 0)
        {
            if(data.top()==mins.top())
                mins.pop();
            data.pop();
        }
        return;
    }
    
    int top() 
    {
        return data.top();
    }
    
    int min() 
    {
        return (data.size() > 0 && mins.size() > 0)?: mins.top():0;
    }
};

leetcode

class MinStack {

    private:
    stack<int> data;
    stack<int> min;
    
    public:
    /** initialize your data structure here. */
    
   
    MinStack() {
    }
    
    void push(int x) {
        
        if(min.empty()||min.top()>=x)
            min.push(x);
        
        data.push(x);
        
    }
    
    void pop() {
        if(data.empty())
            return;
        if(min.top()==data.top())
            min.pop();
        data.pop();
        
    }
    
    int top() {
        
        return data.top();
    }
    
    int getMin() {
        
        return min.size()?min.top():0;
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

 


问题

1.macro  <cassert> assert

void assert (int expression);

Evaluate assertion

If the argument expression of this macro with functional form compares equal to zero (i.e., the expression is false), a message is written to the standard error device and abort is called, terminating the program execution.

The specifics of the message shown depend on the particular library implementation, but it shall at least include: the expression whose assertion failed, the name of the source file, and the line number where it happened. A usual expression format is:

Assertion failed: expression, file filename, line line number 

This macro is disabled if, at the moment of including <assert.h>, a macro with the name NDEBUG has already been defined. This allows for a coder to include as many assert calls as needed in a source code while debugging the program and then disable all of them for the production version by simply including a line like:

 
#define NDEBUG 
 


at the beginning of the code, before the inclusion of <assert.h>.

Therefore, this macro is designed to capture programming errors, not user or run-time errors, since it is generally disabled after a program exits its debugging phase.

 

Parameters

expression

Expression to be evaluated. If this expression evaluates to 0, this causes an assertion failure that terminates the program.

 

Return Value

none

 

Example 

/* assert example */ 
#include <stdio.h> 
/* printf */ 
#include <assert.h> 
/* assert */ 
void print_number(int* myInt) 
{ 
    assert (myInt!=NULL); 
    printf ("%d\n",*myInt); 
} 
int main () 
{ 
    int a=10; 
    int * b = NULL; 
    int * c = NULL; 
    b=&a; 
    print_number (b); 
    print_number (c); 
    return 0; 
}

In this example, assert is used to abort the program execution if print_number is called with a null pointer as attribute. This happens on the second call to the function, which triggers an assertion failure to signal the bug.


2.STL Stack内部实现

deque 是雙向開口的資料結構,若以 deque 為底部結構並封閉其頭端開口,便輕而易舉地形成了一個 stack。

因此, SGI STL 便以 deque 做為預設情況下的 stack 底部結構。

由於 stack 係以底部容器完成其所有工作,而具有這種「修改某物介面,形成另㆒種風貌」之性質者,稱為 adapter(配接器),因此 STL stack 往往不被歸類為 container(容器),而被歸類為 container adapter

stack 所有元素的進出都必須符合「先進後出」的條件,只有 stack 頂端的元素,才有機會被外界取用。 stack 不提供走訪功能,也不提供迭代器


deque adapter

template <class T, class Sequence = deque<T> >
class stack {
// 以下的 __STL_NULL_TMPL_ARGS 會開展為 <>,見 1.9.1 節
friend bool operator== __STL_NULL_TMPL_ARGS (const stack&, const stack&);
friend bool operator< __STL_NULL_TMPL_ARGS (const stack&, const stack&);
public:
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
Sequence c; // 底層容器
public:
// 以下完全利用 Sequence c 的操作,完成 stack 的操作。
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference top() { return c.back(); }
const_reference top() const { return c.back(); }
// deque 是兩頭可進出, stack 是末端進,末端出(所以後進者先出)。
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_back(); }
};
template <class T, class Sequence>
bool operator==(const stack<T, Sequence>& x, const stack<T, Sequence>& y)
{
return x.c == y.c;
}
template <class T, class Sequence>
bool operator<(const stack<T, Sequence>& x, const stack<T, Sequence>& y)
{
return x.c < y.c;
}

 
list adapter

除了 deque 之外, list 也是雙向開口的資料結構。

上述 stack 源碼中使用的底層容器的函式有 empty, size, back, push_back, pop_back,凡此種種 list都具備。

因此若以 list 為底部結構並封閉其頭端開口,一樣能夠輕易形成一個stack

// file : 4stack-test.cpp
#include <stack>
#include <list>
#include <iostream>

#include <algorithm>
using namespace std;
int main()
{
stack<int,list<int> > istack;
istack.push(1);
istack.push(3);
istack.push(5);
istack.push(7);
cout << istack.size() << endl; // 4
cout << istack.top() << endl; // 7
istack.pop(); cout << istack.top() << endl; // 5
istack.pop(); cout << istack.top() << endl; // 3
istack.pop(); cout << istack.top() << endl; // 1
cout << istack.size() << endl; // 1
}

3. Constructing stacks  / C++11

initialize (1)
explicit stack (const container_type& ctnr);

initialized to a copy of ctnr.

move-initialize (2)
explicit stack (container_type&& ctnr = container_type());

acquires the value of ctnr by move-constructing it.

allocator (3)
template <class Alloc> explicit stack (const Alloc& alloc);

constructed with alloc as argument.

init + allocator (4)
template <class Alloc> stack (const container_type& ctnr, const Alloc& alloc);

constructed with cntr and alloc as arguments.

move-init + allocator (5)
template <class Alloc> stack (container_type&& ctnr, const Alloc& alloc);

constructed with std::move(cntr) and alloc as arguments.

copy + allocator (6)
template <class Alloc> stack (const stack& x, const Alloc& alloc);

constructed with x's internal container as first argument and alloc as second.

move + allocator (7)
template <class Alloc> stack (stack&& x, const Alloc& alloc);

constructed by moving x's internal container as first argument and passing alloc as second.

#include <iostream>       // std::cout
#include <stack>          // std::stack
#include <vector>         // std::vector
#include <deque>          // std::deque

int main ()
{
  std::deque<int> mydeque (3,100);          // deque with 3 elements
  std::vector<int> myvector (2,200);        // vector with 2 elements

  std::stack<int> first;                    // empty stack
  std::stack<int> second (mydeque);         // stack initialized to copy of deque

  std::stack<int,std::vector<int> > third;  // empty stack using vector
  std::stack<int,std::vector<int> > fourth (myvector);

  std::cout << "size of first: " << first.size() << '\n';
  std::cout << "size of second: " << second.size() << '\n';
  std::cout << "size of third: " << third.size() << '\n';
  std::cout << "size of fourth: " << fourth.size() << '\n';

  return 0;
}

 Output:

size of first: 0
size of second: 3
size of third: 0
size of fourth: 2

4.Constructing deques / C++11

default (1)
explicit deque (const allocator_type& alloc = allocator_type());

empty container, with no elements.

fill (2)
explicit deque (size_type n);
         deque (size_type n, const value_type& val,
                const allocator_type& alloc = allocator_type());

 n elements. Each element is a copy of val (if provided).

range (3)
template <class InputIterator>
  deque (InputIterator first, InputIterator last,
         const allocator_type& alloc = allocator_type());

as many elements as the range [first,last), with each element emplace-constructed from its corresponding element in that range, in the same order.

copy (4)
deque (const deque& x);
deque (const deque& x, const allocator_type& alloc);

a copy of each of the elements in x, in the same order.

move (5)
deque (deque&& x);
deque (deque&& x, const allocator_type& alloc);

acquires the elements of x.
If alloc is specified and is different from x's allocator, the elements are moved. Otherwise, no elements are constructed (their ownership is directly transferred).
x is left in an unspecified but valid state.

initializer list (6)
deque (initializer_list<value_type> il,
       const allocator_type& alloc = allocator_type());

a copy of each of the elements in il, in the same order.

#include <iostream>
#include <deque>

int main ()
{
  unsigned int i;

  // constructors used in the same order as described above:
  std::deque<int> first;                                // empty deque of ints
  std::deque<int> second (4,100);                       // four ints with value 100
  std::deque<int> third (second.begin(),second.end());  // iterating through second
  std::deque<int> fourth (third);                       // a copy of third

  // the iterator constructor can be used to copy arrays:
  int myints[] = {16,2,77,29};
  std::deque<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );

  std::cout << "The contents of fifth are:";
  for (std::deque<int>::iterator it = fifth.begin(); it!=fifth.end(); ++it)
    std::cout << ' ' << *it;

  std::cout << '\n';

  return 0;
}
Output:
The contents of fifth are: 16 2 77 29

 

 

 

 

posted @ 2019-02-08 13:22 lightmare 阅读(...) 评论(...) 编辑 收藏