为运算表达式设计优先级
难度:
标签:
题目描述
给你一个由数字和运算符组成的字符串 expression
,按不同优先级组合数字和运算符,计算并返回所有可能组合的结果。你可以 按任意顺序 返回答案。
生成的测试用例满足其对应输出值符合 32 位整数范围,不同结果的数量不超过 104
。
示例 1:
输入:expression = "2-1-1" 输出:[0,2] 解释: ((2-1)-1) = 0 (2-(1-1)) = 2
示例 2:
输入:expression = "2*3-4*5" 输出:[-34,-14,-10,-10,10] 解释: (2*(3-(4*5))) = -34 ((2*3)-(4*5)) = -14 ((2*(3-4))*5) = -10 (2*((3-4)*5)) = -10 (((2*3)-4)*5) = 10
提示:
1 <= expression.length <= 20
expression
由数字和算符'+'
、'-'
和'*'
组成。- 输入表达式中的所有整数值在范围
[0, 99]
代码结果
运行时间: 23 ms, 内存: 16.1 MB
/*
题目思路:
1. 使用Java Streams来简化计算过程。
2. 同样的递归思路,不同的是通过Stream来简化List的操作。
3. 对于每个运算符,将表达式分为两部分,使用Stream来处理子表达式的结果组合。
4. 使用Stream的flatMap和map来处理结果的合并和计算。
*/
import java.util.*;
import java.util.stream.*;
public class Solution {
public List<Integer> diffWaysToCompute(String expression) {
List<Integer> result = new ArrayList<>();
for (int i = 0; i < expression.length(); i++) {
char c = expression.charAt(i);
if (c == '+' || c == '-' || c == '*') {
List<Integer> left = diffWaysToCompute(expression.substring(0, i));
List<Integer> right = diffWaysToCompute(expression.substring(i + 1));
result.addAll(
left.stream().flatMap(l -> right.stream().map(r ->
c == '+' ? l + r : c == '-' ? l - r : l * r
)).collect(Collectors.toList())
);
}
}
return result.isEmpty() ? Arrays.asList(Integer.parseInt(expression)) : result;
}
}
解释
方法:
这个题解使用分治算法和记忆化搜索来解决问题。对于给定的表达式,如果它不包含任何运算符,直接将其转换为整数并返回。否则,遍历表达式的每个字符,如果遇到运算符,就将表达式分成左右两部分,递归计算左右两部分的所有可能结果,然后根据运算符对左右两部分的结果进行交叉运算,将所有可能的结果加入答案数组。为了避免重复计算,使用一个字典 memory 来存储已经计算过的子表达式及其结果,这样可以大大减少递归次数,提高效率。
时间复杂度:
O(n * 4^n)
空间复杂度:
O(n * 2^n)
代码细节讲解
🦆
在处理表达式时,如何确保遇到多位数时能正确处理?例如表达式 '10+20' 中的数字处理。
▷🦆
为什么在记忆化搜索中使用字符串作为字典的键,而不是其他数据结构或编码形式?
▷🦆
记忆化搜索中,内存字典的大小可能会对性能产生怎样的影响?是否会因为存储大量结果而导致内存溢出?
▷🦆
在递归分治算法中,每次递归调用时如何处理可能发生的整数溢出问题?
▷相关问题
不同的二叉搜索树 II
给你一个整数 n
,请你生成并返回所有由 n
个节点组成且节点值从 1
到 n
互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。
示例 1:

输入:n = 3 输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]
示例 2:
输入:n = 1 输出:[[1]]
提示:
1 <= n <= 8
基本计算器
给你一个字符串表达式 s
,请你实现一个基本计算器来计算并返回它的值。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval()
。
示例 1:
输入:s = "1 + 1" 输出:2
示例 2:
输入:s = " 2-1 + 2 " 输出:3
示例 3:
输入:s = "(1+(4+5+2)-3)+(6+8)" 输出:23
提示:
1 <= s.length <= 3 * 105
s
由数字、'+'
、'-'
、'('
、')'
、和' '
组成s
表示一个有效的表达式- '+' 不能用作一元运算(例如, "+1" 和
"+(2 + 3)"
无效) - '-' 可以用作一元运算(即 "-1" 和
"-(2 + 3)"
是有效的) - 输入中不存在两个连续的操作符
- 每个数字和运行的计算将适合于一个有符号的 32位 整数
给表达式添加运算符
给定一个仅包含数字 0-9
的字符串 num
和一个目标值整数 target
,在 num
的数字之间添加 二元 运算符(不是一元)+
、-
或 *
,返回 所有 能够得到 target
的表达式。
注意,返回表达式中的操作数 不应该 包含前导零。
示例 1:
输入: num =
"123", target = 6
输出: ["1+2+3", "1*2*3"]
解释: “1*2*3” 和 “1+2+3” 的值都是6。
示例 2:
输入: num =
"232", target = 8
输出: ["2*3+2", "2+3*2"]
解释: “2*3+2” 和 “2+3*2” 的值都是8。
示例 3:
输入: num =
"3456237490", target = 9191
输出: []
解释: 表达式 “3456237490” 无法得到 9191 。
提示:
1 <= num.length <= 10
num
仅含数字-231 <= target <= 231 - 1