package com.freetymekiyan.algorithms.level.hard; import java.util.ArrayList; import java.util.List; /** * 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. * <p> * Examples: * "123", 6 -> ["1+2+3", "1*2*3"] * "232", 8 -> ["2*3+2", "2+3*2"] * "105", 5 -> ["1*0+5","10-5"] * "00", 0 -> ["0+0", "0-0", "0*0"] * "3456237490", 9191 -> [] * <p> * Company Tags: Google, Facebook * Tags: Divide and Conquer * Similar Problems: (M) Evaluate Reverse Polish Notation, (H) Basic Calculator, (M) Basic Calculator II, (M) Different * Ways to Add Parentheses */ public class ExpressionAddOperators { /** * Backtracking. */ public List<String> addOperators(String num, int target) { List<String> res = new ArrayList<>(); backtrack(res, num.toCharArray(), target, 0, new StringBuilder(), 0, 0); return res; } /** * Backtracking. * What kind of data do we need to preserve for between recursive calls? * Of course the result list we are going to generate. * And the original data: the number string and the target. * Then the states of each call, like: * 1. current position in the number string. * 2. the formula generated so far. * 3. the evaluation result of that formula. * 4. For multiplication, it is higher priority than + or -, so need to remember the previous multiplied number. * <p> * Implementation: * Stop when we reach the end of number. * If we found target, add the formula to result. * For each value start from the starting index, parse it to long. * If start is 0, it means the first number. Just add it to path. * Else we search "+", "-", "*" one by one. * For formula just concatenate the number to path with relative operator. * res, num and target are the same. * Next starting position will increment by 1. * Evaluate result will change according to the operator added. * Note that for multiplication, the evaluation result should first minus previous multiplied value. * Then add the product of that value and current value. * The multiplied value should also multiply current value. * * @param res Result paths. * @param num Original number string. Converted to char array for faster speed. * @param target The target value to find. * @param pos Starting index in number string. * @param expr Current expression. * @param eval Actual value of the expression. * @param multed The value to be multiplied in the next recursion. */ private void backtrack(List<String> res, char[] num, int target, int pos, StringBuilder expr, long eval, long multed) { if (pos == num.length) { // Reach the end of num. if (target == eval) { // Found target. res.add(expr.toString()); } return; } long cur = 0; for (int i = pos; i < num.length; i++) { if (num[pos] == '0' && i != pos) { // Avoid multiple digits start with 0. break; } cur = 10 * cur + (num[i] - '0'); // Avoid overflow, along with eval and multed. int len = expr.length(); if (pos == 0) { // First number. backtrack(res, num, target, i + 1, expr.append(cur), cur, cur); expr.setLength(len); // Reset string builder. } else { backtrack(res, num, target, i + 1, expr.append("+").append(cur), eval + cur, cur); expr.setLength(len); backtrack(res, num, target, i + 1, expr.append("-").append(cur), eval - cur, -cur); expr.setLength(len); // For multiplication, eval needs to subtract previous multed first, then add multed * cur // multed just multiply cur backtrack(res, num, target, i + 1, expr.append("*").append(cur), eval - multed + multed * cur, multed * cur); expr.setLength(len); } } } }