一道惰性更新策略的题目

题目来自《程序员面试金典》栈排序

题目描述:

编写程序,对栈进行排序使最小元素位于栈顶。最多只能使用一个其他的临时栈存放数据,但不得将元素复制到别的数据结构(如数组)中。
该栈支持如下操作: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]
说明:

栈中的元素数目在[0, 5000]范围内。

解题思路:

题目的描述是:实现一个API:SortedStack,称为有序栈,内部使用两个栈来进行实现。
一般的思路是:

  1. mainStk维护一个有序的栈,每次push前,先把mainStk栈顶小于当前val的值移动到helpStk
  2. valpushmainStk
  3. 最后把helpStk中的元素push到mainStk中。

思考下是否可以继续优化,
当我们连续push某个值时,其实每次都需要把若干个元素暂时转移到helpStack中。
其实这个过程可以优化为,
当我们push这个值后,不要马上把mainStack恢复到有序的状态,而是根据下一个值的大小,来动态调整,使之mainStack继续满足可以push的状态。比如连续push相同值时,就可以在上个状态结束后,继续push。当我们想要取出最小值时,才将mainStack恢复到有序栈的状态。取出栈顶元素就是最小值。
这种方法其实是一种惰性更新的策略,也就是在真正需要的时候,才继续排序或者转移。类似于linux中的写时复制,在创建一个子进程时,没有马上复制父进程中的内存空间的数据。子进程在只读的情况下,可以沿用父进程中的内存数据。当子进程的内存空间的数据真正改变需要写入的时候,才进行复制。一般称为copy-on-write技术。这种技术提高了linux中进程创建的效率。

解题代码:

push的时候,进行状态调整,使之满足使其满足 helpStack.top() <= val <= mainStack.top(),
然后helpStackmainStack栈中的元素分别是有序的,mainStack栈中的元素是升序的,helpStack栈中的元素是降序的。此时,可以将al值push到mainStack中,则通过这两个栈维护的整个区间元素是有序的。

void push(int val) {
    while(st1.size() && st1.top() < val) {
        st2.push(st1.top());
        st1.pop();
    }

    while(st2.size() && st2.top() > val) {
        st1.push(st2.top());
        st2.pop();
    }

    st1.push(val);
}

peek时,将helpStack元素pushmainStack中,mainStack是有序的,返回栈顶元素即可。

    int peek() {
       while(st2.size()) {
            st1.push(st2.top());
            st2.pop();
        }

        if(st1.size()) {
            return st1.top();
        }

        return -1;
    }
posted @ 2021-02-19 06:48  远跋  阅读(66)  评论(0编辑  收藏  举报