20.有效的括号
-
题目描述:给定一个只包括 ‘(’ , ‘)’ , ‘{’,‘}’,‘[’,‘]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。
示例:
示例1: 输入: "()" 输出: true 示例 2: 输入: "()[]{}" 输出: true 示例 3: 输入: "(]" 输出: false 示例 4: 输入: "([)]" 输出: false 示例 5: 输入: "{[]}" 输出: true
-
思路:遍历字符串,当遇到所有的左括号时,往栈里存与其对应的右括号。当开始遇到右括号时,判断遇到的右括号是否和栈顶元素相同,相同的话就移除此栈顶元素,继续遍历判断下一个;不相同就false了;
-
如果当字符串遍历完,栈中还有元素,代表字符串里有多余的左括号,没有右括号与之能配对
-
如果字符遍历到某处,栈中为空了,代表从此处开始,后面的字符都是多余的右括号了。
class Solution {
public boolean isValid(String s) {
if(s.length() % 2 != 0) {
return false;
}
Stack<Character> stackChar = new Stack<>();
for(int i = 0; i < s.length(); i++) {
if(s.charAt(i) == '(') {
stackChar.push(')');
} else if(s.charAt(i) == '{') {
stackChar.push('}');
} else if(s.charAt(i) == '[') {
stackChar.push(']');
} else if(stackChar.isEmpty() || s.charAt(i) != stackChar.pop()) {
return false;
}
}
return stackChar.isEmpty();
}
}
1047.删除字符串中的所有相邻重复项
-
题目解释:给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。示例:
输入:"abbaca" 输出:"ca" 解释:例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
-
思路:遍历字符串。如果栈中为空或栈顶元素不等于遍历元素,把遍历元素加入到栈中;如果栈顶元素等于遍历元素,则pop后继续遍历。
-
原始思路代码1
class Solution {
public String removeDuplicates(String s) {
Stack<Character> stack = new Stack<>();
for(int i = 0; i < s.length(); i++) {
if(stack.isEmpty() || s.charAt(i) != stack.peek()) {
stack.push(s.charAt(i));
} else {
stack.pop();
}
}
StringBuilder res = new StringBuilder();
while(!stack.isEmpty()) {
res.append(stack.pop());
}
return res.reverse().toString();
}
}
- 直接用字符串当作栈
class Solution {
public String removeDuplicates(String s) {
StringBuilder res = new StringBuilder();
int stackTop = res.length() - 1;
for(int i = 0; i < s.length(); i++) {
if(res.isEmpty() || s.charAt(i) != res.charAt(stackTop)) {
res.append(s.charAt(i));
stackTop++;
} else {
res.deleteCharAt(stackTop);
stackTop--;
}
}
return res.toString();
}
}
150.逆波兰表达式求值
-
题目解释:根据 逆波兰表示法,求表达式的值。
有效的运算符包括 + , - , * , / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例:
示例 1: 输入: ["2", "1", "+", "3", " * "] 输出: 9 解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9 示例 2: 输入: ["4", "13", "5", "/", "+"] 输出: 6 解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6 示例 3: 输入: ["10", "6", "9", "3", "+", "-11", " * ", "/", " * ", "17", "+", "5", "+"] 输出: 22 解释:该算式转化为常见的中缀算术表达式为: ((10 * (6 / ((9 + 3) * -11))) + 17) + 5 = ((10 * (6 / (12 * -11))) + 17) + 5 = ((10 * (6 / -132)) + 17) + 5 = ((10 * 0) + 17) + 5 = (0 + 17) + 5 = 17 + 5 = 22
逆波兰表达式:是一种后缀表达式,所谓后缀就是指运算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack();
for (String s : tokens) {
if ("+".equals(s)) {
stack.push(stack.pop() + stack.pop());
} else if ("-".equals(s)) { //减法时,注意第二个top减去第一个top
stack.push(-stack.pop() + stack.pop());
} else if ("*".equals(s)) {
stack.push(stack.pop() * stack.pop());
} else if ("/".equals(s)) { //除法时,第二个top除以第一个top
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2 / temp1);
} else {
stack.push(Integer.valueOf(s));
}
}
return stack.pop();
}
}