leetcode:282. 给表达式添加运算符

题目来源

题目描述

在这里插入图片描述
在这里插入图片描述

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值