这里要先讲一下Deque实现栈与队列(参考文章)
Java中实际上提供了java.util.Stack来实现栈结构,但官方目前已不推荐使用,而是使用java.util.Deque双端队列来实现队列与栈的各种需求
ava.util.Deque的实现子类有
java.util.LinkedList //基于链表,
java.util.ArrayDeque //基于数组实现的双端队列.
Deque总体介绍
要讲栈和队列,首先要讲Deque接口。Deque的含义是“double ended queue”,即双端队列,它既可以当作栈使用,也可以当作队列使用。
- 下表列出了Deque与Stack相对应的接口:
- 下表列出了Deque与Queue相对应的接口:
上面两个表共定义了Deque的12个接口。添加,删除,取值都有两套接口,它们功能相同,区别是对失败情况的处理不同。一套接口遇到失败就会抛出异常,另一套遇到失败会返回特殊值(false或null)。除非某种实现对容量有限制,大多数情况下,添加操作是不会失败的。虽然Deque的接口有12个之多,但无非就是对容器的两端进行操作,或添加,或删除,或查看。明白了这一点讲解起来就会非常简单。
ArrayDeque和LinkedList是Deque的实现子类,他们都能使用Deque的这12个方法,包括isEmpty()判断是否为空方法和size()栈和队列的大小。
ArrayDeque
从名字可以看出ArrayDeque底层通过数组实现,为了满足可以同时在数组两端插入或删除元素的需求,该数组还必须是循环的,即循环数组(circular array),也就是说数组的任何一点都可能被看作起点或者终点。ArrayDeque是非线程安全的(not thread-safe),当多个线程同时使用的时候,需要程序员手动同步;另外,该容器不允许放入null元素。
LinkedList
LinkedList实现了Deque接口,因此其具备双端队列的特性,由于其是链表结构,,双向链表,因此不像ArrayDeque要考虑越界问题,容量问题,那么对应操作就很简单了(另外当需要使用栈和队列是官方推荐的是ArrayDeque)。
20. 有效的括号
leetcode链接
思路: 括号匹配是使用栈解决的经典问题。
建议在写代码之前要分析好有哪几种不匹配的情况,如果不在动手之前分析好,写出的代码也会有很多问题。
我们的代码只要覆盖了这三种不匹配的情况,就不会出问题,可以看出 动手之前分析好题目的重要性。
-
第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false
-
第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false
-
第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false
那么什么时候说明左括号和右括号全都匹配了呢,就是字符串遍历完之后,栈是空的,就说明全都匹配了。
java代码实现
class Solution {
public boolean isValid(String s) {
Deque<Character> stack=new LinkedList<>();
for(int i=0;i<s.length();i++){
char ch=s.charAt(i);
if(ch=='('){
stack.push(')');
}else if(ch=='{'){
stack.push('}');
}else if(ch=='['){
stack.push(']');
}else if(stack.isEmpty() || stack.peek()!=ch){
return false;
}else{
stack.pop();
}
}
return stack.isEmpty();
}
}
时间复杂度:O(n)
空间复杂度:O(n)
1047. 删除字符串中的所有相邻重复项
思路: 用栈实现相邻元素是否相同的判断,和有效括号的思路类似。
java代码实现
class Solution {
public String removeDuplicates(String s) {
Deque<Character> stack=new ArrayDeque<>();
for(int i=0;i<s.length();i++){
char ch=s.charAt(i);
if(stack.isEmpty() || stack.peek()!=ch){
stack.push(ch);
}else{
stack.pop();
}
}
String res="";
while(!stack.isEmpty()){
res=stack.pop()+res;
}
return res;
}
}
时间复杂度:O(n)
空间复杂度:O(n)
150. 逆波兰表达式求值
思路: 栈的典型使用
注意:
- 注意 - 和/ 需要特殊处理
- leetcode 内置jdk的问题,不能使用==判断字符串是否相等
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack=new LinkedList<>();
for(String s:tokens){
if(s.equals("+")){
stack.push(stack.pop()+stack.pop());
}else if(s.equals("*")){
stack.push(stack.pop()*stack.pop());
}else if(s.equals("-")){
int temp1=stack.pop();
int temp2=stack.pop();
stack.push(temp2-temp1);
}else if(s.equals("/")){
int temp1=stack.pop();
int temp2=stack.pop();
stack.push(temp2/temp1);
}else{
stack.push(Integer.valueOf(s));
}
}
return stack.pop();
}
}
时间复杂度:O(n)
空间复杂度:O(n)