题目来源:https://leetcode-cn.com/problems/expression-add-operators/
大致题意:
给定一个数字组成的字符串 num 和一个目标整数 target,在 num 之间添加 +、 -、 * 三类运算符将 num 变为一个表达式,使表达式的运算结果等于 target,找出所有这样的表达式
思路
用枚举递归,类似 dfs 的方式遍历所有组合,输出满足条件的表达式
枚举 + 递归
枚举:枚举下一个操作数,从只占当前位到从当前位到末尾位置都为该操作数
递归:对于当前枚举的操作数。递归 +、 -、 * 三类运算符的运算结果
使用一个递归函数 recursion(expr, idx, res, mul) 来进行递归结果的计算,其中 expr 为当前的的表达式,idx 为字符串 num 的遍历位置,res 是当前的临时结果,mul 为末尾的连乘结果(乘法优先级高,用来在添加 * 运算符的时候做结果转换)
接下来,看代码:
class Solution {
private int n; // 给定数字串的长度
private int target; // 给定的目标值
private String num; // 给定的数字串
private List<String> ans; // 存储符合条件的运算串
public List<String> addOperators(String num, int target) {
this.n = num.length();
this.num = num;
this.target = target;
this.ans = new ArrayList<>();
StringBuffer sb = new StringBuffer();
recursion_track(sb, 0, 0, 0);
return ans;
}
public void recursion_track(StringBuffer expr, int i, long res, long mul) {
if (i == n) { // 若数字串递归结束且当前递归的运算结果与 target 相同
if (res == target) { // 将本次递归的表达式放入答案集合
ans.add(expr.toString());
}
return;
}
// 存下本轮递归添加运算符的索引位置,也是本层递归开始添加字符串的位置
int opIndex = expr.length();
// 第一个数字前不能有符号
// 如果索引大于 0,也就是说不是第一个数字的位置,提前占位
if (opIndex > 0) {
expr.append(0);
}
// 从当前位开始,本次运算截取的数字
long val = 0;
// 枚举本层添加的数字
// 截取多个字符作为本层数字时,要确保首位字符不为 0
for (int j = i; j < n && (j == i || num.charAt(i) != '0'); j++) {
// 更新截取的数字值
val = val * 10 + num.charAt(j) - '0';
// 将截取的当前位字符放入表达式
expr.append(num.charAt(j));
// 若是第一个数字,直接添加
if (i == 0) {
recursion_track(expr, j + 1, val, val);
} else { // 不是第一个数字,递归添加三种运算符的表达式
expr.setCharAt(opIndex, '+');
recursion_track(expr, j + 1, res + val, val);
expr.setCharAt(opIndex, '-');
recursion_track(expr, j + 1, res - val, -val);
expr.setCharAt(opIndex, '*');
recursion_track(expr, j + 1, res - mul + mul * val, mul * val);
}
}
// 回溯,需要将本层递归添加的字符串去掉
expr.setLength(opIndex);
}
}