题目来源
题目描述
class Solution {
public:
vector<string> addOperators(string num, int target) {
}
};
题目解析
回溯
我们先来考虑只有加法和减法时。
- 思路:
- 添加一个符号,在添加一个数字,计算到目前为止表达式的结果
- 当到达字符串末尾的时候,判断当前结果是否等于target
- 注意:
- 选取第一个数字的时候不加符号,剩下的都是符号 + 数字的形式
- 因为将字符串转成整数时用int可能会溢出,以及计算到目前为止表达式的结构也可能超过int范围,所以这两个值都用long
- 注意没有
01
这样的数字
class Solution {
// path: 目前为止的表达式
// 字符串开始的位置
// eval 目前为止计算的结果
void process(string num, int target, vector<string> &ans, string path, int start, int eval){
if(start == num.size()){
if(target == eval){
ans.push_back(path);
}
return;
}
for (int i = start; i < num.size(); ++i) {
// 不包含前导0
if(num[start] == '0' && i > start){
break;
}
long cur = stol(num.substr(start, i - start + 1));
if(start == 0){ // 选取第一个数不加符号
process(num, target, ans, path + std::to_string(cur), i + 1, cur );
}else{
process(num, target, ans, path + "+" + std::to_string(cur), i + 1, eval + cur);
process(num, target, ans, path + "-" + std::to_string(cur), i + 1, eval - cur);
}
}
}
public:
vector<string> addOperators(string num, int target) {
vector<string> ans;
process(num, target, ans, "", 0, 0);
return ans;
}
};
现在考虑乘法有什么不同。
还是以 123 为例。如果还是按照上边的代码的逻辑,如果添加乘法的话就是下边的样子。
1
/
+2(3)
/
*3(9)
也就是 1 +2 *3 = 9,很明显是错的,原因就在于乘法的优先级较高,并不能直接将前边的结果乘上当前的数。而是用当前数乘以前一个操作数。
算的话,我们可以用之前的值(3)减去前一个操作数(2),然后再加上当前数(3)乘以前一个操作数(2)。即,3 - 2 + 3 * 2 = 7
所以代码的话,我们需要添加一个 pre 参数,用来记录上一个操作数。
对于加法和乘法,上一个操作数我们根据符号直接返回 -2,3 这种就可以了,但对于乘法有些不同。
如果是连乘的情况,比如对于 2345,假设之前已经进行到了 2 +3 *4 (14),现在到 5 了。
如果我们想增加乘号,计算表达式 2 +3 *4 *5 的值。5 的前一个操作数是 *4 ,我们应该记录的值是 3 * 4 = 12 。这样的话才能套用上边的讲的公式。
用之前的值(14)减去前一个操作数(12),然后再加上当前数(5)乘以前一个操作数(12)。
即,14 - 12 + 5 * 12 = 62。也就是 2 +3 *4 *5 = 62。
可以结合代码再看一下。
class Solution {
// path: 目前为止的表达式
// 字符串开始的位置
// eval 目前为止计算的结果
void process(string num, int target, vector<string> &ans, string path, int start, int eval, long prev){
if(start == num.size()){
if(target == eval){
ans.push_back(path);
}
return;
}
for (int i = start; i < num.size(); ++i) {
// 不包含前导0
if(num[start] == '0' && i > start){
break;
}
long cur = stol(num.substr(start, i - start + 1));
if(start == 0){ // 选取第一个数不加符号
process(num, target, ans, path + std::to_string(cur), i + 1, cur, cur );
}else{
process(num, target, ans, path + "+" + std::to_string(cur), i + 1, eval + cur, +cur);
process(num, target, ans, path + "-" + std::to_string(cur), i + 1, eval - cur, -cur);
//乘法有两点不同
//当前表达式的值就是 先减去之前的值,然后加上 当前值和前边的操作数相乘
//eval - pre + pre * cur
//另外 addOperatorsHelper 函数传进 pre 参数需要是 pre * cur
//比如前边讲的 2+ 3 * 4 * 5 这种连乘的情况
process(num, target, ans, path + "*" + std::to_string(cur), i + 1, eval - prev + prev * cur, prev * cur);
}
}
}
public:
vector<string> addOperators(string num, int target) {
vector<string> ans;
process(num, target, ans, "", 0, 0, 0);
return ans;
}
};
类似题目
题目 | 思路 |
---|---|
leetcode:150. 后缀表达式求和 Evaluate Reverse Polish Notation | |
leetcode:面试题 16.26. 计算器 calculator-lcci |