结构设计

  • 栈:先进后出FILO

  • 队列:先进先出FIFO

  • 准备两个栈,一个数据栈data,一个辅助栈help

    • push时,只需要向help栈中推

    • pop时,只要去data的栈顶元素,即data.pop(),但是data栈没有元素了需要怎样?将help栈的元素不断往data栈推,推完为止,如果data,help栈均无元素,报错

    • peek时,与pop的过程一样,只是在返回的时候,data.peek()

    • empty,当data,help均为空时,返回true

 class MyQueue {
        Stack<Integer> data;
        Stack<Integer> help;
 
        public MyQueue() {
            data = new Stack<>();
            help = new Stack<>();
        }

        public void push(int x) {
            help.push(x);
        }

        public int pop() {
            if (data.isEmpty() && help.isEmpty()) throw new RuntimeException("empty queue");
            if (data.isEmpty()) {
                while (!help.isEmpty()) data.push(help.pop());
            }
            return data.pop();
        }

        public int peek() {
            if (data.isEmpty() && help.isEmpty()) throw new RuntimeException("empty queue");
            if (data.isEmpty()) {
                while (!help.isEmpty()) data.push(help.pop());
            }
            return data.peek();
        }

        public boolean empty() {
            return data.isEmpty() && help.isEmpty();
        }
    }

方法1:Stack

  • 参考「232. 用栈实现队列」

方法2:Deque

方法1:两个队列

  • 队列是先进先出,栈是先进后出,在top()方法中,为了避免,数据拷贝,有一个swap()的动作,datahelp的存储顺序是一样的

  • 因为data队列的元素始终存在,判断栈是否为空的时候,只需要关注size(data)==0

  • top()pop()方法只是在弹出data的最后一个元素的时候是否要继续放回help队列

方法2:一个队列

  • shift()方法是为top()pop()方法准备的,做一件事:就是弹出队头到倒数第2个队尾元素的,将其送到队列的尾部,在执行top()pop(),弹出queue的队头元素,如果是top(),继续保留这个元素,pop()时扔掉

方法1:辅助栈[浪费空间]

  • 基础版辅助栈,准备一个data, 数据栈,准备一个help 辅助栈

  • 其中data的存数据的,help辅助栈用来存最小值,在push操作时,help如果栈顶元素大于待push的元素,将待push的元素塞进help中,如果不是,则重复塞一次help的栈顶元素,注意help为空的时候特殊处理下

  • 准备两个栈,data和help,做push操作时,需要保持help栈顶的元素始终最小,data的数据正常推入,help栈顶维持最小,在执行getMin方法的时候,返回help的栈顶元素

方法2:辅助栈[不浪费空间]

  • 升级版本辅助栈,当push 进去的时候,

    • help的栈顶元素比新来的元素小的时候,这个时候保持help不变

    • help的栈顶元素大于等于新来的元素时,help同步要推一份新的元素进来

    • help元素为空的时候,也需要往里推

  • pop的时候,pop的元素是否和help 的元素有重叠,有就将help的元素pop出去,没有就维持不动,data栈正常pop

方法1:二分

方法2:线段树

需要一个哈希双端链表,DoubleLinkedNode

这个双端链表有下面的几个属性

将新加入的节点插入到双端链表的头部位置addFirst(node)

image-20200904085250881.png

移除一个节点removeNode(node)

image-20200904090539191.png

弹出最末尾的节点,并返回最后的节点popLast

将一个已经在链表中存在的节点移动到链表的开头moveToHead(node)

  • 先移除这个节点移除,再将这个节点添加到链表的开头

下面开始LRU

思路

初始化

  • 注意head节点和tail节点需要new出来

get(key)

  • 如果cache中不存在key,返回-1

  • 如果cache中存在,取出这个节点,将节点moveToHead,返回节点的值

put(k,v)

  • 取出节点,分节点存在与否讨论:

    • 节点不存在:新创建节点,将该节点插入到链表的头部,并将其putcache

      • 做一个额外的判断:如果当前的cache的大小大于capacity,需要移除最末尾的节点,链表和$cache$都要做移除操作

    • 节点存在:返回节点的值,将节点移动到链表头部

方法1:模拟

Last updated