题目链接如下为运算表达式设计优先级
给你一个由数字和运算符组成的字符串 expression ,按不同优先级组合数字和运算符,计算并返回所有可能组合的结果。你可以 按任意顺序 返回答案。
生成的测试用例满足其对应输出值符合 32 位整数范围,不同结果的数量不超过 104 。
下面是测试样例
输入:expression = "2-1-1"
输出:[0,2]
解释:
((2-1)-1) = 0
(2-(1-1)) = 2
错误思路:写这道题的第一反应是看到数据长度为20,一想那直接dfs就好了,在dfs的时候把按照符号栈弹出和不弹出两种情况。但是存在一个问题在符号栈弹出的时候,是否需要递归的对之前的符号栈进行弹出,如果不弹出,则会漏掉一些情况。
那么应该怎么做呢?
这道题的思路其实是采用分治的思路,看作两段表达式通过符号合并。就可以拆成三种情况
e
x
p
r
e
s
s
i
o
n
1
+
e
x
p
r
e
s
s
i
o
n
2
expression1+expression2
expression1+expression2,
e
x
p
r
e
s
s
i
o
n
1
−
e
x
p
r
e
s
s
i
o
n
2
expression1-expression2
expression1−expression2,
e
x
p
r
e
s
s
i
o
n
1
∗
e
x
p
r
e
s
s
i
o
n
2
expression1*expression2
expression1∗expression2。分别求
e
x
p
r
e
s
s
i
o
n
1
expression1
expression1和
e
x
p
r
e
s
s
i
o
n
2
expression2
expression2的值再进行组合合并就行。
在中间
e
x
p
r
e
s
s
i
o
n
1
expression1
expression1和
e
x
p
r
e
s
s
i
o
n
2
expression2
expression2的值可能会计算多次,因此可以用unordered_map
去先存储中间值。
class Solution {
public:
unordered_map<string, vector<int>> mp;
vector<int> diffWaysToCompute(string expression) {
int n = expression.size();
return func(expression, 0, expression.size()-1);
}
int f(int val1, int val2, char op){
if(op=='+') return val1 + val2;
if(op=='-') return val1 - val2;
if(op=='*') return val1 * val2;
return 0;
}
vector<int> func(string expression, int from, int to){
vector<int> ans;
if(from>to) return {};
if(from==to) return {expression[from]-'0'};
if(from+1==to) return {(expression[from]-'0')*10+expression[to]-'0'};
if(mp.find(expression.substr(from, to-from+1))!=mp.end()) return mp[expression.substr(from, to-from+1)];
for(int i=from; i<=to; ++i){
char c = expression[i];
if(c=='+' || c=='*' || c=='-'){
vector<int> ans1 = func(expression, from, i-1);
vector<int> ans2 =func(expression, i+1, to);
for(auto i:ans1){
for(auto j:ans2){
ans.push_back(f(i,j,c));
}
}
}
}
mp[expression.substr(from, to-from+1)] = ans;
return ans;
}
};
最后总结一下采用分治思路的题目有什么特点:
大问题可以分成多个子问题解决,子问题通过一些操作可以合并成大问题
这里就是将大表达式看作了多个小表达式求和/差/乘积