Given a string num
that contains only digits and an integer target
, return all possibilities to insert the binary operators '+'
, '-'
, and/or '*'
between the digits of num
so that the resultant expression evaluates to the target
value.
Note that operands in the returned expressions should not contain leading zeros.
Example 1:
Input: num = "123", target = 6 Output: ["1*2*3","1+2+3"] Explanation: Both "1*2*3" and "1+2+3" evaluate to 6.
Example 2:
Input: num = "232", target = 8 Output: ["2*3+2","2+3*2"] Explanation: Both "2*3+2" and "2+3*2" evaluate to 8.
Example 3:
Input: num = "3456237490", target = 9191 Output: [] Explanation: There are no expressions that can be created from "3456237490" to evaluate to 9191.
Constraints:
1 <= num.length <= 10
num
consists of only digits.-231 <= target <= 231 - 1
This problem asks us to find all valid expressions formed by inserting '+', '-', and '*' operators between the digits of a given number string num
such that the expression evaluates to a given target value.
The most efficient way to solve this problem is using backtracking. We explore all possible combinations of operators and operands recursively.
Algorithm:
Base Case: If we've processed all digits in num
, check if the current expression evaluates to the target. If it does, add the expression to the result list.
Recursive Step: For each digit (or consecutive digits forming a number) starting from the current position:
Handling Leading Zeros: We need to ensure that operands don't start with '0' (except for '0' itself). This is handled by checking num[u] == '0'
and breaking the loop if it's true and not the first digit of the current number.
Code (Python):
class Solution:
def addOperators(self, num: str, target: int) -> List[str]:
ans = []
def dfs(u, prev, curr, path): # u: index, prev: previous operand, curr: current expression value, path:expression string
if u == len(num):
if curr == target:
ans.append(path)
return
for i in range(u, len(num)):
if i != u and num[u] == '0': #Handle leading zeros
break
next = int(num[u : i + 1])
if u == 0:
dfs(i + 1, next, next, path + str(next)) #First operand
else:
dfs(i + 1, next, curr + next, path + "+" + str(next)) #Addition
dfs(i + 1, -next, curr - next, path + "-" + str(next)) #Subtraction
dfs(i + 1, prev * next, curr - prev + prev * next, path + "*" + str(next)) #Multiplication
dfs(0, 0, 0, "")
return ans
Code (Java):
class Solution {
private List<String> ans;
private String num;
private int target;
public List<String> addOperators(String num, int target) {
ans = new ArrayList<>();
this.num = num;
this.target = target;
dfs(0, 0L, 0L, ""); // Use long to handle potential overflow
return ans;
}
private void dfs(int u, long prev, long curr, String path) {
if (u == num.length()) {
if (curr == target) ans.add(path);
return;
}
for (int i = u; i < num.length(); i++) {
if (i != u && num.charAt(u) == '0') break; //Handle leading zeros
long next = Long.parseLong(num.substring(u, i + 1));
if (u == 0) dfs(i + 1, next, next, String.valueOf(next));
else {
dfs(i + 1, next, curr + next, path + "+" + next);
dfs(i + 1, -next, curr - next, path + "-" + next);
dfs(i + 1, prev * next, curr - prev + prev * next, path + "*" + next);
}
}
}
}
Time Complexity: O(4^N * N), where N is the length of num
. The 4 comes from the four possibilities at each position (+, -, *, or nothing for the first digit). The N factor comes from the potential length of the numbers formed by consecutive digits. The complexity is not strictly O(4^N) because the number of recursive calls is affected by the actual digits and the target.
Space Complexity: O(N) for the recursion stack and to store the result list. The space used by the result list is proportional to the number of valid expressions, which can be at most O(4^N).
The C# solution provided in the original response is significantly different, it uses a dynamic programming approach with memoization. While this approach can be efficient in certain scenarios, it involves more complex data structures and could be harder to understand than a straightforward recursive backtracking solution. I recommend using backtracking as it is generally simpler to implement and comprehend for this problem.