《面试题 03.05. 栈排序》——惰性更新

栈排序。 编写程序,对栈进行排序使最小元素位于栈顶。最多只能使用一个其他的临时栈存放数据,但不得将元素复制到别的数据结构(如数组)中。该栈支持如下操作:push、pop、peek 和 isEmpty。当栈为空时,peek 返回 -1。

示例1

 输入:
["SortedStack", "push", "push", "peek", "pop", "peek"]
[[], [1], [2], [], [], []]
 输出:
[null,null,null,1,null,2]

 

 

示例2

 输入: 
["SortedStack", "pop", "pop", "push", "pop", "isEmpty"]
[[], [], [], [1], [], []]
 输出:
[null,null,null,null,null,true]

 

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-of-stacks-lcci

 

这个题目最容易想到的办法是我们使用一个辅助栈,当push的val比当前栈顶元素大时,就先将当前栈中比val大的元素push到辅助栈中,然后当前栈压入val,再将辅助栈中的元素重新压回当前栈,这样就保证了栈顶元素一定是最小的。具体c++代码实现如下:

 1 class SortedStack {
 2     stack<int> st;
 3 public:
 4     SortedStack() {
 5     }
 6 
 7     void push(int val) {
 8         if(st.empty()||val<=st.top())
 9         {
10             st.push(val);
11         }
12         else
13         {
14             stack<int> tmp;
15             while(!st.empty()&&st.top()<val)
16             {
17                 tmp.push(st.top());
18                 st.pop();
19             }
20             st.push(val);
21             while(!tmp.empty())
22             {
23                 st.push(tmp.top());
24                 tmp.pop();
25             }
26         }
27     }
28     
29     void pop() {
30         if(st.empty()){cout<<"empty";return;}
31         st.pop();
32     }
33     
34     int peek() {
35         if(st.empty()){return -1;}
36         return st.top();
37     }
38     
39     bool isEmpty() {
40         return st.empty();
41     }
42 };
43 
44 /**
45  * Your SortedStack object will be instantiated and called as such:
46  * SortedStack* obj = new SortedStack();
47  * obj->push(val);
48  * obj->pop();
49  * int param_3 = obj->peek();
50  * bool param_4 = obj->isEmpty();
51  */

  我们压入一个长度为n的升序序列,那么第i次push操作,我们将进行i次pop()和i次push()操作,总的操作次数将高达n^2次,效率实在是不高。仔细一想,如果出现连续的push()工作,而每一次我们都从当前栈倒出一部分,装入val,再将辅助栈中的元素倒回,我们不妨假设:

*某一次push的val_1,它应处于位置 x (1<=x<=n+1,当前已有n个元素), 我们需要进行的push、pop操作是(n+1-x)*2+1,

*接着,下一次的val_2,它应处于位置y(1<=y<=n+2,当前已有n+1个元素),我们需要进行的push、pop操作是(n+1-y)*2+1;

  值得思考的是,这两次操作中我们是否做了多余的工作?答案是肯定的。试想一下,若我们在找到val_1的位置后,暂时保留辅助栈中的元素,下一次的val_2,如果val_2>val_1,意味着我们只需要把辅助栈中比val_2大的几个元素push进原始栈,然后就可以得到val_2的位置,这其中的操作量大大减少了。两个栈不再是你满我空,你空我满的状态,而是达到了一种微妙的平衡,这个平衡就是,原始栈中的元素>=val>辅助栈中的元素。辅助栈自底向上逐渐增大,原始栈自顶向下逐渐增大。这样,当需要最小元素时,在辅助栈底或原始栈顶取得。

class SortedStack {
    stack<int> sortStack;
    stack<int> helpStack;
public:
    SortedStack() {
    }
    void push(int val) {
        int Max = sortStack.empty() ? INT_MAX : sortStack.top();
        int Min = helpStack.empty() ? INT_MIN : helpStack.top();
        while(true)
        {
            if(val > Max)
            {
                helpStack.push(sortStack.top());
                sortStack.pop();
                Max = sortStack.empty() ? INT_MAX : sortStack.top();
            }
            else if(val < Min)
            {
                sortStack.push(helpStack.top());
                helpStack.pop();
                Min = helpStack.empty() ? INT_MIN : helpStack.top();
            }
            else
            {
                sortStack.push(val);
                break;
            }//此时已经满足(elems in sortStack)>= val >(elems in helpstack);
        }
    }
    
    void pop() {
        while(!helpStack.empty())
        {
            sortStack.push(helpStack.top());
            helpStack.pop();
        }                                          //辅助栈中的元素压回原始栈中
        if(!sortStack.empty())
            sortStack.pop();
    }
    
    int peek() {
        while(!helpStack.empty())
        {
            sortStack.push(helpStack.top());
            helpStack.pop();
        }                                       //辅助栈中的元素压回原始栈中

        return sortStack.empty() ? -1 : sortStack.top();
    }
    
    bool isEmpty() {
        return sortStack.empty()&&helpStack.empty();
    }
};

就很nice

posted @ 2020-03-30 23:20  鳄鱼四驱车  阅读(262)  评论(0编辑  收藏  举报