给定一个正确的表达式(不用担心不规范的输入),比如2-1-1, 通过在不同位置添加左右括号,改变求值的优先级顺序,求出所有的这些值;
Example 1
Input: "2-1-1"
.
((2-1)-1) = 0
(2-(1-1)) = 2
Output: [0, 2]
Example 2
Input: "2*3-4*5"
(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10
Output: [-34, -14, -10, -10, 10]
这个题目应该没有便捷的解法,只能全部的都尝试一遍;当然仅仅需要暴力的枚举一遍,也没有什么有趣的地方,我觉得有趣的地方体现在下面两点:
1. 这个题目可以用递归的方法求解,因为,假设遇到某个操作符,如果知道了左边的结果,再计算出右边的结果,那么只要把左右两边的结果合并起来,就可以了;
2. 当然如果直接按照递归去做,会出现一个问题,(大概会超时,我没有提交这样的代码);假设在得到了某个操作符两边的结果后,到了下一个操作符,递归计算的时候,任然会需要前面一个操作符(左边的)的结果,所以必须要把已经计算过的结果要cache起来;
最后的代码如下:
private final static long base = 100001;
private Map<Long, List<Integer>> cache = new HashMap<>();
private List<Integer> diffWaysToCompute(char[] cs, int start, int end) {
long key = base * start + end;
if (cache.containsKey(key)) {
return cache.get(key);
}
boolean isNumber = true;
for (int i = start; i < end; i++) {
if (isOperator(cs[i])) {
isNumber = false;
break;
}
}
List<Integer> result = new ArrayList<>();
if (isNumber) {
result.addAll(toNum(cs, start, end));
} else {
for (int i = start; i < end; i++) {
if (isOperator(cs[i])) {
List<Integer> prev = diffWaysToCompute(cs, start, i);
List<Integer> suff = diffWaysToCompute(cs, i + 1, end);
result.addAll(combineResult(prev, suff, cs[i]));
}
}
return result;
}
cache.put(key, result);
return result;
}
private List<Integer> combineResult(List<Integer> prev, List<Integer> suff, char op) {
List<Integer> result = new ArrayList<>();
for (int x : prev) {
for (int y : suff) {
result.add(calculate(x, y, op));
}
}
return result;
}
private int calculate(int x, int y, char op) {
switch (op) {
case '+':
return x + y;
case '-':
return x - y;
case '*':
return x * y;
}
return 0;
}
private List<Integer> toNum(char[] cs, int start, int end) {
int num = 0;
for (int i = start; i < end; i++) {
if (cs[i] == ' ') {
continue;
}
num = num * 10 + (cs[i] - '0');
}
List<Integer> result = new ArrayList<>(1);
result.add(num);
return result;
}
private boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*';
}
public List<Integer> diffWaysToCompute(String input) {
return diffWaysToCompute(input.toCharArray(), 0, input.length());
}
public static void main(String[] args) {
Solution solution = new Solution();
System.out.println(solution.diffWaysToCompute("2-4").stream().map(x -> "" + x).collect(Collectors.joining(",")));
}
再仔细想想,这种需要cache之前结果的递归算法,应该是可以用动态规划的方式表达出来的。可惜我不擅长动态规划,就不费脑力了~~~