写在前面的话:因为是第一次刷leetcode,不明白题目中测试用例的意思,在评论区看到有人解读,故在此记录一下。本博客旨在总结思路及收获,详细解法请参考官网众网友的题解。
输入:
["CQueue","appendTail","deleteHead","deleteHead"]
[[],[3],[],[]]
输出:[null,null,3,-1]
输入的第一行代表操作,第二行执行这个操作的参数;输出的行表示对应操作的结果。
即:CQueue 表示新建一个CQueue对象,不需要输入参数,结果也无返回值。
appendTail 表示执行一个appendTail(value)操作,输入的参数是3,该操作结束后也无返回值。
deleteHead 表示执行一个deleteHead()操作,无输入参数,输出结果是队头数据3。
下一个deleteHead同理,返回的是-1,表示队空。
-
思路:队列:FIFO;栈:LIFO。
官方的解法是每次插入之前都要将栈1的元素全部pop出push至栈2,插入后再从栈2pop出,入栈1,这样保证新插入的数据始终在栈底,栈1的栈顶元素实际是队头元素,做删除操作时直接对栈1的栈顶元素pop即可。 -
我的解法
插入数据在栈1中直接插入,
删除队头元素时
if(栈2为空 栈1不为空) 将栈1中所有元素pop并push至栈2,再pop栈2的栈顶元素;
if(栈2不为空) 直接pop栈2的栈顶元素;
if(栈2,栈1均为空) 即队列空,返回-1。
- 代码
class CQueue {
private Stack<Integer> s1;
private Stack<Integer> s2;
private int size;
public CQueue(){
this.s1 = new Stack<Integer>();
this.s2 = new Stack<Integer>();
this.size = 0;
}
public void appendTail(int value) {
this.s1.push(value);
this.size++;
}
public int deleteHead() {
if(!this.s2.empty()){
this.size--;
return this.s2.pop();
}else if(!this.s1.empty()) {
while(!this.s1.empty())
this.s2.push(s1.pop());
this.size--;
return this.s2.pop();
}else{
return -1;
}
}
}
- 时间复杂度:插入:O(1) ;删除:最坏的情况是O(N)
- 空间复杂度:O(N)
- 遇到的问题总结
- Syntax error on token “.”, @ expected after this token:要把代码写在主方法里头
- 判断Stack为空时,
s.empty()
方法和s.isEmpty()
的区别:无本质区别,只是存在的类不同,一个在java.util.Stack
类中,一个在java.util.Vector
类中,且class Stack<E> extends Vector<E>
。 - 评论中有这样一段话:
“使用java的同学请注意,如果你使用Stack的方式来做这道题,会造成速度较慢; 原因的话是Stack继承了Vector类,而Vector底层是一个Object[]数组,那么就要考虑空间扩容和移位的问题了。 可以使用LinkedList来做Stack的容器,因为LinkedList实现了Deque接口,所以Stack能做的事LinkedList都能做,其本身结构是个双向链表,扩容消耗少。”
的确,栈除顺序栈外,还有链栈,题目并没有说只能用顺序栈实现,所以也可以像这个同学说的用链表LinkedList实现,只要按照栈的操作来操作即可(可以翻评论理解) - 为何Vector会比LinkedList慢,我也不是很懂,参考的文章有:
java集合系列之Vector(源码分析)
java常用数据结构之Vector&Stack
详解Java中ArrayList、Vector、LinkedList三者的异同点
5.什么是线程安全?