282. Expression Add Operators

282. Expression Add Operators


Given a string that contains only digits 0-9 and a target value, return all possibilities to add binary operators (not unary) +, -, or * between the digits so they evaluate to the target value.

Example 1:

Input: num = "123", target = 6
Output: ["1+2+3", "1*2*3"] 

Example 2:

Input: num = "232", target = 8
Output: ["2*3+2", "2+3*2"]

Example 3:

Input: num = "105", target = 5
Output: ["1*0+5","10-5"]

Example 4:

Input: num = "00", target = 0
Output: ["0+0", "0-0", "0*0"]

Example 5:

Input: num = "3456237490", target = 9191
Output: []

方法1: backtracking

grandyang: http://www.cnblogs.com/grandyang/p/4814506.html
花花:https://www.youtube.com/watch?v=v05R1OIIg08

思路:

传说中的24点题,答案能抽丝剥茧事无巨细真的非常厉害。首先一串数字可以有很多种切分方法,也有三种运算符,每一种都要dfs下去,所以确定基本思路是backtracking,而backtracking的基本单位是 operator + operand。那么我们要传递给下一层dfs哪些参数呢?首先是operator:三种选择,operand:从当前位置开始要切多少个digit出来,所有这些的combination都要递归下去。除此以外,本层还要传递之前累计计算的结果,那么如果下面一层继续+/-运算,结果可以直接累计;但如果下一层想要*运算,就必须把前一个运算单位和再之前的分割开来。举个栗子:2 + 3 * 5 , 如果往下直接传 2 + 3的结果,乘法是无法继续的,必须告知下一层优先级运算的当前结果,也就是+3,才可能用5 - 3 + 3 * 5 = 17 计算。 如果是连乘的情况呢? 举个栗子:2 + 3 * 4 * 5, 首先5 - 3 + 3 * 4 = 14, 这时为了能连乘,我们要传递的乘法优先级tmp是3 * 4, 那么下一步可以14 - 12 + 12 * 5 = 62。总结来讲dfs应该有如下几个参数:

  1. num:input
  2. target:input
  3. curNum: 之前累计的结果:已经激进的累计了上一个单位
  4. diff:保留着所有乘法至今所累加的diff
  5. current:一个string来记录表达式
  6. result:遍历到底层时需要push current

易错点

  1. edge case: 第一个划分出来的数字必须以“+”为operator
  2. “00000”, “003”:这种切分出来的不合法数字要跳过
  3. num == target : 采用len = 1 to num.size()的方式cover
  4. 推送条件
  5. 乘法的递推计算
  6. stoi会造成overflow,要用stoll

Complexity

Time complexity: O(n * 4 ^ (n - 1)),参见花花的slide。本质上是在n个数字的n-1个间隙中插入“”,“+”,“-”,“* ”四种字符,空字符表示前后连成一个长数字。每一个这样的表达式都是在一次O(n)的遍历中搜出来的,所以是O(n * 4 ^ (n - 1))。如果选择在得到完整表达式之后用basic calculator的方法来evaluate,需要O(n^2)
Space complexity: O(n), 递归的深度最多是O(n),注意dfs在每一个时间点,都仅保存着当前的string。

class Solution {
public:
    vector<string> addOperators(string num, int target) {
        vector<string> result;
        addHelper(num, target, 0, 0, "", result);
        return result;
    }
    
    void addHelper(string num, int target, int diff, long curNum, string current, vector<string> & result) {
        if (num.size() == 0 && curNum == target) {
            result.push_back(current);
            return;
        }
        
        for (int len = 1; len <= num.size(); len++) {
            string cur = num.substr(0, len);
            string next = num.substr(len);
            if (cur[0] == '0' && cur.size() > 1) continue;
            if (current.size() > 0) {
                addHelper(next, target, stoll(cur), curNum + stoll(cur), current + "+" + cur, result);
                addHelper(next, target, -stoll(cur), curNum - stoll(cur), current + "-" + cur, result);
                addHelper(next, target, diff * stoll(cur), curNum - diff + diff * stoll(cur), current + "*" + cur, result);
            }
            else {
            	// 这里为什么要单独处理呢?第一是因为起始的数字前面不应该加符号,其次要加只能implicitly加“+”,如果“*”和前面的diff(初始化为0)不正确的抵消掉,会产生错误值
                addHelper(next, target, stoll(cur), curNum + stoll(cur), cur, result);
            }
        }
        return;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值