第十一天| 第五章 栈与队列part 02 20.有效的括号 1047.删除字符串中的所有相邻重复项 150.逆波兰表达式求值
20.有效的括号
-
题目链接:https://leetcode.cn/problems/valid-parentheses/
-
文章讲解:https://programmercarl.com/0020.%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7.html
-
题目介绍:给定一个只包括
'('
,')'
,'{'
,'}'
,'['
,']'
的字符串s
,判断字符串是否有效。- 有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
- 有效字符串需满足:
-
解法:
-
括号匹配是使用栈解决的经典问题。
-
再举个例子,linux系统中,cd这个进入目录的命令我们应该再熟悉不过了。
cd a/b/c/../../
这个命令最后进入a目录,系统是如何知道进入了a目录呢 ,这就是栈的应用(其实可以出一道相应的面试题了)
-
-
思路:存在三种情况,不满足括号匹配,分别是1. 左括号多了,2 右括号多了,3 括号不匹配
- 采用的方法是,遇到左括号就把应该对应的那种右括号push到栈中,当遇到右括号时,与当前的栈顶比较一下,如果相同说明匹配,不相同说明不匹配(这里解决了问题三);
- 如果还在遍历的过程中,但是栈已经空了,说明右括号多了,所以通过判断循环中的栈是否为空,决定右括号是不是多了(这里解决了问题2);
- 如果遍历完了,栈不空,说明左括号多了(这里解决了问题1).
- 如果都没事,返回true。
-
-
代码:
-
class Solution { public boolean isValid(String s) { Stack<Character> stack = new Stack<>(); char[] chars = s.toCharArray(); for (int i = 0; i < chars.length; i++) { if (chars[i] == '{') { stack.push('}'); } else if (chars[i] == '[') { stack.push(']'); } else if (chars[i] == '(') { stack.push(')'); // 这里是处理右括号多和左右括号不匹配 // 如果右括号多,那么栈已经是空的了,没东西给你pop,因为没有对应的左括号,只有有对应的左括号的情况下,遍历到右括号的时候才会pop。而此已经将匹配好的右括号全部pop出去了,当再次遍历到右括号的时候,没有右括号可以pop // 如果栈顶和当前的右括号不相同,说明不匹配,因为题目明确要求了左括号以正确的顺序闭合。 } else if (stack.isEmpty() || stack.peek() != chars[i]) { return false; } else { stack.pop(); } } // 如果最后遍历完之后,栈里面还有数据,说明左括号多 if (!stack.isEmpty()) { return false; } return true; } }
-
1047.删除字符串中的所有相邻重复项
-
题目链接:https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/
-
文章讲解:https://programmercarl.com/1047.%E5%88%A0%E9%99%A4%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E7%9B%B8%E9%82%BB%E9%87%8D%E5%A4%8D%E9%A1%B9.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
-
题目介绍:给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
-
在 S 上反复执行重复项删除操作,直到无法继续删除。
-
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
-
示例:
输入:"abbaca" 输出:"ca" 解释: 例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
-
-
解法:
- 定义一个栈,只要栈不是空的或者栈里面的元素和当前遍历的元素不相同,就把这个元素push到栈里面。如果遇到和当前遍历的元素相同,就pop出来这个元素,最后栈里剩下的元素倒序之后就是删除所有相邻重复项的有效字符串。
-
代码:
-
class Solution { public String removeDuplicates(String s) { Stack<Character> stack = new Stack<>(); char[] chars = s.toCharArray(); for (int i = 0; i < chars.length; i++) { if (stack.isEmpty() || stack.peek() != chars[i]) { stack.push(chars[i]); } else { stack.pop(); } } String str = ""; while (!stack.isEmpty()) { str = stack.pop() + str; } return str; } }
-
150.逆波兰表达式求值
-
题目链接:https://leetcode.cn/problems/evaluate-reverse-polish-notation/
-
文章讲解:https://programmercarl.com/0150.%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B1%82%E5%80%BC.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
-
题目介绍:给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。请你计算该表达式。返回一个表示表达式值的整数。
- 注意:
- 有效的算符为 ‘+’、‘-’、‘*’ 和 ‘/’ 。
- 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式。
- 答案及所有中间计算结果可以用 32 位 整数表示。
- 注意:
-
解法:定义一个栈,用来存放数字。遇到数字就push进栈,遇到操作符就pop出栈,并将计算的结果pop进栈。最后,将栈中的最后一个元素返回就是最终的计算结果。
-
代码:
-
class Solution { public int evalRPN(String[] tokens) { Stack<Integer> stack = new Stack<>(); 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("-")) { stack.push(-stack.pop() + stack.pop()); } 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(); } }
-
总结:只要是相邻元素的消除都要用到栈
- 根据以上的栈的操作可以发现,只要是相邻元素的消除都要用到栈,例如第一题中的括号匹配就是用消除相匹配的括号,第二题相邻相同的元素用栈来消除,第三题数字遇到操作符用栈来消除。