第五章 栈与队列part02
今日内容:
- 20. 有效的括号
- 1047. 删除字符串中的所有相邻重复项
- 150. 逆波兰表达式求值
20. 有效的括号
题目:给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
分析有哪几种不匹配的情况:
第一种情况,字符串里左方向的括号多余了 ,所以不匹配。
第二种情况,括号没有多余,但是 括号的类型没有匹配上。
第三种情况,字符串里右方向的括号多余了,所以不匹配。
第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false
第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false
第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false
字符串遍历完之后,栈是空的,就说明全都匹配了。
class Solution {
public boolean isValid(String s) {
Deque<Character> deq = new LinkedList<>();
int length = s.length();
for(int i=0;i<length;i++)
{
char ch = s.charAt(i);
if(ch=='(') deq.push(')');
else if(ch=='[') deq.push(']');
else if(ch=='{') deq.push('}');
else if(deq.isEmpty()||deq.pop()!=ch) return false;
}
return deq.isEmpty();
}
}
1047. 删除字符串中的所有相邻重复项
题目:给出由小写字母组成的字符串 S
,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
栈的目的,就是存放遍历过的元素,当遍历当前的这个元素的时候,去栈里看一下我们是不是遍历过相同数值的相邻元素。然后再去做对应的消除操作。
从栈中弹出剩余元素因为从栈里弹出的元素是倒序的,所以再对字符串进行反转一下,就得到了最终的结果。
ArrayDeque会比LinkedList在除了删除元素这一点外会快一点
ArrayDeque 作为 堆栈(FILO) 使用时的方法:
堆栈方法 | 等效的双端队列方法 |
push(e) | addFirst(e) |
pop(e) | removeFirst(e) |
peek() | peekFirst() |
①使用 Deque 作为堆栈
class Solution {
public String removeDuplicates(String s) {
ArrayDeque<Character> deq = new ArrayDeque<>();
for(int i=0;i<s.length();i++)
{
char ch = s.charAt(i);
if(deq.isEmpty()||ch!=deq.peek()) deq.push(ch);
else deq.pop();
}
String result ="";
while(!deq.isEmpty()) result=deq.pop()+result;
return result;
}
}
②拿字符串直接作为栈
class Solution {
public String removeDuplicates(String s) {
StringBuffer result = new StringBuffer();
int top = -1;
for(int i=0;i<s.length();i++)
{
char ch = s.charAt(i);
if(top>=0&&ch==result.charAt(top))
{
result.deleteCharAt(top);
top--;
}
else{
result.append(ch);
top++;
}
}
return result.toString();
}
}
delete()方法和deleteCharAt()方法都是用来删除StringBuffer字符串指定字符索引的方法。
delete(int a,int b)方法:包含两个参数,使用时删除索引从a到b(包括a不包括b)的所有字符;
deleteCharAt(int s)方法:只有一个参数,使用时删除索引为a的字符。
③双指针;
class Solution {
public String removeDuplicates(String s) {
char[] chars =s.toCharArray();
int slow = 0;
for(int fast=0;fast<chars.length;fast++)
{
chars[slow] = chars[fast];
if(slow>0&&chars[slow]==chars[slow-1]) slow--;
else slow++;
}
return new String(chars,0,slow);
}
}
4.String s = new String(char数组,起始下标,长度);左闭右开。
150. 逆波兰表达式求值
题目:给你一个字符串数组 tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
逆波兰表达式相当于是二叉树中的后序遍历。
将中缀表达式,转化为后缀表达式之后计算机可以利用栈来顺序处理,不需要考虑优先级了。也不用回退了, 所以后缀表达式对计算机来说是非常友好的。
在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么这岂不就是一个相邻字符串消除的过程,和1047.删除字符串中的所有相邻重复项中的对对碰游戏是不是就非常像了。
这和1047. 删除字符串中的所有相邻重复项是差不多的,只不过本题不要相邻元素做消除了,而是做运算!
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList<>();
for(String s:tokens)
{
if("+".equals(s)) stack.push(stack.pop()+stack.pop());
else if("-".equals(s))stack.push(-stack.pop()+stack.pop());
else if("*".equals(s))stack.push(stack.pop()*stack.pop());
else if("/".equals(s)){
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2/temp1);
}
else{
stack.push(Integer.valueOf(s));
}
}
return Integer.valueOf(stack.pop());
}
}