java中栈的数据结构是Stack,代码中使用的几个方法:
push(x):将x压入栈
pop():将栈顶元素弹出并返回该栈顶元素的值
empty():判断栈是否为空
peek():只返回栈顶元素的值,但是不弹出该元素
这个队列由st1、st2两个栈实现,其中st1表示输入栈,用来存输入到队列中的数据,st2表示输出栈,每次数据出队列,就从st2栈顶使用pop()方法出栈。
对于pop()方法的实现,我一开始的想法是,模拟入队列就是直接往st1里面push,模拟出队列因为要先进先出(FIFO),而栈又只能先进后出(FILO),因此每次出队列的时候都把st1的数全都放到st2中,取出栈顶元素,即队首元素后再把st2中元素全放回st1中。
为什么会这么想我也不知道,绝了,而且执行用时居然也是0ms,但是每次都要来回倒数据,真的离谱,但凡数据量大点肯定撑不住了。
就。。看了看人家想的。。果然。。
直接判断一下st2里面是不是空的就好了呀!!!如果不空就直接出栈,这时候肯定是队首元素,如果空了就把st1里的数据全转移过去,这样st1栈底元素也就是此时的队首就成了st2栈顶元素,直接弹出就好了。
empty()就看两个栈是不是同时是空的就好了,但凡一个栈有数据,队列肯定不是空的。
还有一点就是,这段代码中存在重复代码,可以抽取成一个函数,就不用重复写了。
class MyQueue {
Stack<Integer> st1;
Stack<Integer> st2;
public MyQueue() {
st1 = new Stack<>();
st2 = new Stack<>();
}
public void push(int x) {
st1.push(x);
}
public int pop() {
if(st2.empty()){
while(!st1.empty()){
int temp = st1.pop();
st2.push(temp);
}
}
int start = st2.pop();
return start;
}
public int peek() {
if(st2.empty()){
while(!st1.empty()){
int temp = st1.pop();
st2.push(temp);
}
}
return st2.peek();
}
public boolean empty() {
return st1.empty() && st2.empty();
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty();
*/
emmm有个小问题,就是为什么在类里创建了一个Stack对象,又到了构造方法里才用new创建一个栈呢,为啥不在类里面直接new好,等解决这个问题回来回答,嘤嘤嘤。
还有个问题,官解用的是Deque<Integer> inStack; inStack = new ArrayDeque<Integer>();为什么不用Stack呢,qwq。问题太多了
!!!!!这个题,这个题,有个好思路真的很重要,我自己想了半天都没搞明白,写了依托答辩,最后跑出来是错的,放上来做个错误的示范。。
当时怎么想的类,又想多了,大概就是新元素都放到q1里,q1每多一个元素size就++,当要pop的时候,就从q1里取元素放到q2直到q1只剩一个元素,就把这个元素poll出去,再把q2里的数据放回q1。要peek的时候还要更复杂一点,因为q1剩的那个元素不会被poll出去,所以拿到这个元素的值之后还要把这个放到q2,再把q2里的所有元素放回q1,就。。很复杂。。脑子怎么长的呀哇哇哇!!
错误的输入是:
["MyStack","push","push","pop","top"]
[[],[1],[2],[],[]]
但是其实我害不知道为啥子错啊,可能还得再想想,报的错是peek() return的null。
class MyStack {
Queue<Integer> q1;
Queue<Integer> q2;
int size;
public MyStack() {
q1 = new LinkedList<>();
q2 = new LinkedList<>();
size = 0;
}
public void push(int x) {
q1.add(x);
size++;
}
public int pop() {
while(size > 1){
q2.add(q1.poll());
size--;
}
int result = q1.poll();
while(!q2.isEmpty()){
q1.add(q2.poll());
size++;
}
return result;
}
public int top() {
while(size > 1){
q2.add(q1.poll());
size--;
}
int result = q1.peek();
q2.add(q1.poll());
size--;
while(!q2.isEmpty()){
q1.add(q2.poll());
size++;
}
return result;
}
public boolean empty() {
return q1.isEmpty();
}
}
看了题解才发现原来就是好简单,只需要在添加元素的时候借助队列q2修改一下队列q1让他符合栈后进先出(LIFO)的特点就好了,其他的不管是取栈顶元素值,还是弹出栈顶元素,都直接在q1中的队首元素处进行操作。只用实现push(x)这个方法!!!
实现细节:新来的元素添加到q2里,这样这个新元素从q2出去的时候一定是第一个出去的,符合了后进先出原则。再把q1里的元素都挪到q2新放进来的元素后面,最后创建一个新的临时队列变量,把q2中的所有元素都转移到q1中去。这样下一次再在q2中加入一个新元素的时候,这个新元素又会成为队首元素,也就是栈中第一个出去的栈顶元素。
根据这一思路,q1中的全部元素都已经是按照栈的顺序排好的了,从队首取元素,就相当于从栈顶取元素。判断栈是否为空,也只需要判断q1这个队列是否为空就行,q2只是起到一个辅助作用。
class MyStack {
Queue<Integer> q1;
Queue<Integer> q2;
public MyStack() {
q1 = new LinkedList<Integer>();
q2 = new LinkedList<Integer>();
}
public void push(int x) {
q2.add(x);
while (!q1.isEmpty()) {
q2.add(q1.poll());
}
Queue<Integer> temp = q1;
q1 = q2;
q2 = temp;
}
public int pop() {
return q1.poll();
}
public int top() {
return q1.peek();
}
public boolean empty() {
return q1.isEmpty();
}
}