LeetCode:282. Expression Add Operators

在这里插入图片描述

这题第一反应还是使用回溯法,相当于把所有情况全部列举出来,但是做的时候有许多细节需要注意。

直接看代码:

class Solution {
public:
    vector<string> addOperators(string num, int target) {
        vector<string> res;
        backtrack(res, num, target, 0, 0, "", 0, '#');
        return res;
    }
private:
    void backtrack(vector<string> &res, const string &num, const int &target, long long val, int index, string exp, const long long pv, const char op) {
        if (index >= num.size() && val == target) {
            res.push_back(exp);
            return;
        }
        for (int l = 1; index + l <= num.size(); ++l) {
            string thisVal = num.substr(index, l);
            long long thisNum = stol(thisVal);
            if (to_string(thisNum).size() != thisVal.size()) continue;
            if (index == 0) 
                backtrack(res, num, target, val+thisNum, index+l, exp+thisVal, thisNum, '#');
            else {
                backtrack(res, num, target, val+thisNum, index+l, exp+"+"+thisVal, thisNum, '+');
                backtrack(res, num, target, val-thisNum, index+l, exp+"-"+thisVal, thisNum, '-');
                backtrack(res, num, target, (op == '-')? val+pv-pv*thisNum : (op == '+')? val-pv+pv*thisNum : val*thisNum, index+l, exp+"*"+thisVal, pv*thisNum, op);//很多细节
            }
        }
    }
};

有这么几点需要注意:
1.关于stol函数:很方便,可以直接将string转化为long,第一次使用
2.关于数字开头为0的解决方法:这个问题应该是经常会遇到的,这里的解决方法是

if (to_string(thisNum).size() != thisVal.size()) continue;

将string转化为数字之后再转化为string,看看string大小是否与之前还相等。如果不等,说明数字的开头有0被省略了。确实是个很巧妙的方法,以后可以使用,当然也可以直接检测string的首字母是否为’0’。
当然,相比于如何解决,更重要的是知道在什么场合下需要注意这个问题,依我看来,在string和数字相互转换的场合下,需要注意首字母为0的问题。
3.相对于这一题很重要的一点:如果我们不特殊处理一下乘法引起的计算顺序改变的问题,会将2+3*2计算为(2+3)*2。我一开始就中招了,下面是我一开始的代码:

class Solution {//!!!这个代码是错误的
public:
    vector<string> addOperators(string num, int target) {
        vector<string> res;
        backtrack(res, num, target, 0, 0, "");
        return res;
    }
private:
    void backtrack(vector<string> &res, const string &num, const int &target, long long val, int index, string exp) {
        if (index >= num.size() && val == target) {
            res.push_back(exp);
            return;
        }
        for (int l = 1; index + l <= num.size(); ++l) {
            string thisVal = num.substr(index, l);
            long long thisNum = stol(thisVal);
            cout << "val:" << val << " thisNum: " << thisNum << endl;
            if (index == 0) 
                backtrack(res, num, target, val+thisNum, index+l, exp+thisVal);
            else {
                backtrack(res, num, target, val+thisNum, index+l, exp+"+"+thisVal);
                backtrack(res, num, target, val-thisNum, index+l, exp+"-"+thisVal);
                backtrack(res, num, target, val*thisNum, index+l, exp+"*"+thisVal);
            }
        }
    }
};

所以我们需要记录一下之前的操作数和操作符,就像第一段代码那样,在乘法时做特殊处理。

更新:
更加清楚的版本:

class Solution {
public:
    vector<string> addOperators(string num, int target) {
        vector<string> ret;
        helper(ret, "", 0, 0, '+', target, num, 0);
        return ret;
    }
private:
    void helper(vector<string>& ret, string temp, long long tempRes, long long lastVal, char lastOp, int target, string& str, int idx) {
        if (idx == str.size()) {
            if (tempRes == target)
                ret.push_back(std::move(temp));
            return;
        }
        for (int j = idx; j <= str.size(); ++j) {
            string ss = str.substr(idx, j-idx+1);
            long long v = stol(ss);
            if (idx == 0) 
                helper(ret, ss, v, v, '+', target, str, j+1);
            else {
                helper(ret, temp+"+"+ss, tempRes+v, v, '+', target, str, j+1);
                helper(ret, temp+"-"+ss, tempRes-v, v, '-', target, str, j+1);
                if (lastOp == '+')
                    helper(ret, temp+"*"+ss, tempRes-lastVal+lastVal*v, lastVal*v, '+', target, str, j+1);
                else
                    helper(ret, temp+"*"+ss, tempRes+lastVal-lastVal*v, lastVal*v, '-', target, str, j+1);
            }
            if (j == idx && str[j] == '0')
                return;
        }
    }
};

这里防止前置0的方法更加简单,直接判断第一个数是不是0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值