摘要
算法训练营第11天算法学习的日常记录。今天的题目是leetcode的三道题:20. 有效的括号、1047. 删除字符串中的所有相邻重复项、150. 逆波兰表达式求值。本文从思路分析上阐述了解题步骤,并进行了具体的Java代码实现。
20、有效的括号
思路分析
这是一道非常经典的栈的题目。我们发现,如果一大堆括号,都是有效括号的话,那么左右括号一定是一一对应的。比如,一对小括号内一定不能出现单个的左中括号,或右大括号。
因此不难想到,当我们读取到左括号('(', '[', '{'
)时,就将它们压入栈stack
。当读取到右括号(')', ']', '}'
)时,就将stack
的栈顶元素弹出。
如果栈为空,那就说明没有左括号与当前右括号匹配。如果不为空,就检查弹出的左括号与当前右括号是否匹配,如果是,就继续这两个过程,如果否,就说明是无效括号。
当所有的字符读取完之后,还要检查栈是否为空,也就是是否有左括号没匹配完。
代码实现
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '(', '[', '{':
stack.push(c);
break;
default:
if (stack.isEmpty()) {
return false;
}
switch (stack.pop()) {
case '(':
if (c != ')') return false;
break;
case '[':
if (c != ']') return false;
break;
case '{':
if (c != '}') return false;
break;
default:
}
}
}
return stack.isEmpty();
}
1047、删除字符串中的所有相邻重复项
思路分析
这道题要求删除相邻的相同字符。因此不难想到使用栈的特性便于解题。
遍历字符串。
如果栈为空或者当前字符与栈顶元素不同,就将字符压入栈中。
如果当前字符与栈顶元素相同,就将栈顶弹出,并继续遍历下一个字符。
代码实现
思路非常清晰。但在Java中,如果使用Stack
类作为栈,我们解这道题的最后还需要使用StringBuilder
类来拼接字符串,并且因为栈后进先出的特性,还要让StringBuilder
类完成一次反转操作,耗费时间空间。
因此本文选择直接使用StringBuilder
类完成栈的操作,相当于用链表实现栈,并且因为只需要操作链表尾部元素,从而时间复杂度较低。
public String removeDuplicates(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (!sb.isEmpty() && sb.charAt(sb.length() - 1) == s.charAt(i)) {
sb.deleteCharAt(sb.length() - 1);
} else {
sb.append(s.charAt(i));
}
}
return sb.toString();
}
150、逆波兰表达式求值
思路分析
不难发现,逆波兰表达式的写法与栈的后进先出的特性简直如出一辙,这是因为逆波兰表达式本就是为计算机设计的!
对于一个逆波兰表达式[a,b,+]
,我们只需要在遍历到数字a
、b
时进行压栈,在遍历到操作服+
时,将a
、b
弹出,分别作为+
的操作数即可。
那对于复杂一点的逆波兰表达式[c,a,b,+,-]
,又该如何操作呢?
同样的,遍历到数字,就压栈;遍历到操作符,就弹出两个元素作为操作数,计算的也就是a+b
。
计算完成后,再将a+b
的结果压栈,此时栈中元素为c
、a+b
。
遍历到-
时,将计算c-(a+b)
,此时弹出两个元素,依次为a+b
、c
。这就启示我们:先弹出的元素要放到操作符右边,后弹出的元素放到操作符左边。
当所有的字符遍历结束后,栈中剩下的元素就是完全的计算结果了。
代码实现
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
for (String token : tokens) {
int ans;
if (token.chars().allMatch(Character::isDigit)) {
ans = Integer.parseInt(token);
} else {
ans = cal(stack.pop(), stack.pop(), token);
}
stack.push(ans);
}
return stack.pop();
}
private int cal(int b, int a, String op) {
return switch (op) {
case "+" -> a + b;
case "-" -> a - b;
case "*" -> a * b;
case "/" -> a / b;
default -> throw new IllegalStateException("Unexpected value: " + op);
};
}
总结和思考
以上就是今天的算法学习记录,我们通过分析思路和实现代码的方式,解决了这三道题目。希望对大家的算法学习有所帮助,谢谢阅读!