根据中缀表达式构造二叉表达式树
难度:
标签:
题目描述
代码结果
运行时间: 35 ms, 内存: 0.0 MB
/*
* 思路:
* 1. 将中缀表达式转换为后缀表达式(逆波兰表达式)。
* 2. 使用栈构建二叉表达式树。
*
* 第一步:
* - 使用栈和优先级规则将中缀表达式转换为后缀表达式。
*
* 第二步:
* - 使用一个栈来构建树。当遇到操作数时,创建一个叶节点并推入栈中。
* - 当遇到运算符时,弹出栈顶的两个节点作为该运算符的子节点,创建一个新节点并将其推入栈中。
*/
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class TreeNode {
char val;
TreeNode left;
TreeNode right;
TreeNode(char x) { val = x; }
}
class Solution {
public TreeNode expTree(String s) {
List<Character> postfix = infixToPostfix(s);
Deque<TreeNode> stack = new ArrayDeque<>();
postfix.forEach(c -> {
if (Character.isDigit(c)) {
stack.push(new TreeNode(c));
} else {
TreeNode node = new TreeNode(c);
node.right = stack.pop();
node.left = stack.pop();
stack.push(node);
}
});
return stack.peek();
}
private List<Character> infixToPostfix(String s) {
Deque<Character> stack = new ArrayDeque<>();
Map<Character, Integer> precedence = Map.of(
'+', 1, '-', 1, '*', 2, '/', 2, '(', 0
);
return IntStream.range(0, s.length())
.mapToObj(s::charAt)
.flatMap(c -> {
if (Character.isDigit(c)) {
return Stream.of(c);
} else if (c == '(') {
stack.push(c);
return Stream.empty();
} else if (c == ')') {
List<Character> list = new ArrayList<>();
while (!stack.isEmpty() && stack.peek() != '(') {
list.add(stack.pop());
}
stack.pop();
return list.stream();
} else {
List<Character> list = new ArrayList<>();
while (!stack.isEmpty() && precedence.get(stack.peek()) >= precedence.get(c)) {
list.add(stack.pop());
}
stack.push(c);
return list.stream();
}
})
.collect(Collectors.toList());
}
}
解释
方法:
这个题解采用了两个栈(操作符栈 ops 和数字栈 nums)来处理并构造表达式树。数字栈用于存储表达式中的数字(或已构造的子表达式树),而操作符栈用于存储操作符。在遍历输入字符串 s 时,根据字符的类型(数字、操作符、括号)进行不同的操作:
1. 数字直接转换为树节点并压入 nums 栈。
2. 操作符 '+', '-' 时,如果 ops 栈顶的操作符为 '+', '-', '*', '/', 需要进行计算以保持操作符的优先级,然后将当前操作符压栈。
3. 操作符 '*', '/' 类似,但只比较栈顶是否为 '*', '/', 因为这两者优先级更高。
4. 左括号 '(' 直接压栈,表示优先级的提升。
5. 右括号 ')' 表示一个括号内的表达式结束,需要执行计算直到遇到左括号。遇到左括号后,将其出栈。
最后,如果操作符栈中还有剩余操作符,继续执行计算,直到栈为空。最终,nums 栈顶的节点即为根节点。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
在处理操作符 '+' 和 '-' 时,为什么需要检查并可能执行 mock_compute 函数,而处理 '*' 和 '/' 时只检查栈顶为 '*' 或 '/'?
▷🦆
算法中如何处理数字多位的情况,例如 '23' 或 '105',因为示例中只提到了单个字符的数字处理?
▷🦆
mock_compute 函数在遇到右括号 ')' 时如何确保所有在括号内的操作符都被处理掉,尤其是考虑到嵌套括号的情况?
▷🦆
在遍历完成输入字符串后,直接返回 nums 栈顶元素作为根节点是否安全?是否存在 nums 栈为空的情况?
▷