1.题目链接:232. 用栈实现队列
题目描述:
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明:
你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
基础:
栈的创建对象---Stack<栈中元素类型> 栈名= new Stack<>();
可以调用的方法:stack.push()----压栈,即在末尾插入元素
stack.pop()---删除栈中头位置的元素并返回被删除的值
stack.peek()---返回栈中首位的值
stack.isEmpty()----判断是否为空
解法:
要用两个栈来实现一个队列,一个入栈,一个出栈。
入栈和队列的入栈一样。
而出栈则需要将元素顺序改变成和队列出栈的顺序一样。
这里就用到了循环。如果出栈outStack.isEmpty(),就将入栈中元素反序加入出栈中,即将入栈头位置的元素加到出栈的末尾,并将入栈中的头位置元素删掉。即while(!InStack.isEmpty()){outStack.push(inStack.pop())}这样就能保证出栈顺序和队列一致了。
下面为代码(java):
2.题目链接:225. 用队列实现栈
题目描述:
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
注意:
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
基础:
①队列有Queue和Deque(双端队列)两种,前者只能先入先出,后者可以实现在先入先出也可以实现后入先出。
②前者是链表结构,后者是数组结构,即 Queue<队列元素类型> 队列名 = new LinkedList<>(),Deque<队列中元素类型> 队列名 = new ArrayDeque<>()。
③前者可调用函数:
queue.offer() ---实现进队列,即插入元素在队列末尾;
queue.poll()---实现删除队列头的元素并返回被删除的值;
queue.peek()---返回队列的头位置的元素值;queue.size()---队列长度;
queue.isEmpty()---判断是否为空。
④后者可以调用函数:
deque.addLast()---在队列末尾插入元素;
deque.addFirst()---在队列头插入元素;
deque.pollFirst()---在队列头删除元素并返回被删除的值;
deque.pollLast()---在队列尾删除元素并返回被删除的值;
deque.peekFirst()---返回队列头位置的元素;
deque.peekLast()---返回队列末位置的元素值;
deque.size()---队列长度;
deque.isEmpty()---判断是否为空。
解法:
①可以用两个队列实现栈,也可以用一个队列实现栈。而用每种方法,都可以分别用两种队列的结果,即Queue和Deque。
②但要想到不管是用一个队列还是两个队列,如果用Queue的队列结构来实现,其末尾位置的值取不到---即栈的头位置取不到,此时就要在插入元素的时候,将队列的顺序变成栈的顺序。
③而用Deque结构则可以获取到队列末尾位置的值,所以插入的时候正常操作,而要删除头位置元素(即弹栈)的时候,要将除最后一个元素外的元素放到另一个队列中或者放到同一个队列的末尾,然后弹出剩余的最后一个元素即可。
用两个队列实现栈:
1)用queue:
①即要在offer()的时候就要将顺序改变。即定义一个原队列queue和辅助队列queue1,如果在一个队列中操作即是保持新插入的元素位置不变,将前面的元素都弹出并加到该队列的后方。
②但此时我们用两个队列,故将一个队列中的元素反序复制到辅助序列,最后再交换就可以了。
③故让新插入的元素直接插入到queue1即辅助队列中保持不变。然后queue1.offer(queue.pop()),什么时候循环结束呢就是while(!queue.isEmpty)即当原序列中没有元素的时候就停止。
④最后将queue和queue1交换,交换的过程中保证了辅助队列一直是空队列。而原队列的出栈顺序此时和栈就相同了。即原队列变成了倒序的了。
⑤此时栈的首位置就是队列的首位置。
下面为代码(java):
2)用deque:
①此时插入的时候一致了,只需要在弹栈的时候,进行改变就行。
②还是两个队列,将原队列中除最后一个位置的元素都弹出并在辅助队列中addLast,然后定义result = 此时的原队列.pollFirst(),最后返回result。
③此时原队列变成了空队列,最后将原队列和辅助队列交互,保证了辅助队列一直为空队列,而交换后的原队列相当于去掉了队列的尾----即栈的首位置。
④此时栈的首位置可以直接调用deque.peekLast()来获得。
用一个队列实现:
1)用Queue:
①此时offer()的时候就要处理,即保证新插入的元素位置不动,将其前面的元素弹出并加到队列的末尾,循环条件为size > 1,因为要保证新插入的元素位置不动同时也保证了从第二个元素开始,每加入一个元素都要这样做,最后得到的就是一个和反序的队列。
②此时栈头的位置就是队列头的位置。故获取或删除可以直接queue.poll();
下面为代码(java):
2)用Deque:
①插入的时候不用处理,而弹出的时候要处理。同样保持最后一个元素位置不变,将其前面的所有元素弹出队列并再加到队列的末尾,然后定义result = deque.pollFirst(),最后返回它。此时队列相当于删除了队列末尾---即栈的头。
②而栈的头位置的值可以通过队列尾来知道即 deque.peekLast();
下面为代码(java):
总结:
①用队列实现栈---用queue其实就是将插入的元素位置不动,将其前面的都弹出并加到后面去。而对于用两个队列来实现栈,插入元素位置不动就是将新插入的元素插入到辅助队列中,然后将原队列的加到新辅助队列的末尾,最后互换原队列和辅助队列。而对于一个队列就是,while(队列的size>1)。
②用队列实现栈---用deque可以像文章中提到的那种思想,保持最后一个元素不动,弹出前面的元素加到后面(一个队列)或者加到辅助序列中(两个队列),最后返回此时原队列的剩下那个元素。其实也可以直接调用deque.pollLast()直接删,所以用双端队列其实写起来很简单。
③用栈实现队列---关键就是如何将入栈的元素倒序的放到出栈中,循环条件为if(出栈.isEmpty()),将入栈里的所有元素加到出栈中。