题意:
给定一个算式(运算符号限为加减乘),用括号来限定其运算顺序,返回所有可能结果。
分析:
这个题拿着,举个例子研究下,比如 2 * 3 - 4 * 5,研究一下所加的括号,发现括号的大小,个数,位置等等与字符串长度的关系,但是很快发现这没什么用,这是一些数学规律,但是程序和数学是有很大区别的!程序有计算机帮助我们解决问题,所以我们应该从更宏观,更直接的层面和角度来思考如何解决一个问题。
我们的一个字符串,不同的划分,可以有很多种运算可能,我们要搜索(列举)出所有的可能,因为这个搜索不知道次数,只知道结束条件,很容易就想到递归。这时候找规律,发现可以分区间,第一个数一个括号,后面剩下的的一个括号, 前两个数一个括号,后面剩下的一个括号(两部分各有很多种可能,我们取其笛卡尔积即可)。而程序思维和数学思维的区别这里就体现了:程序思维是宏观的控制者的思维,我只关心划分了两个区间,就可以通过两个区间的笛卡尔积得到结果,而不关心每个区间怎么求,有什么微观的数学规律.......
所以不管是分治,动态规划,贪心,XX搜索, 递归等等,我认为其实都是一种宏观的核心的共通的算法思想,只是具体形式有区别。都是针对一个问题解决,一般的情况下的子问题怎么推广到问题的全局域。
所以我们重新整理思路:
我们要搜索一个字符串所有的组合方式,那么就是要找把这个字符串划分为两部分,两部分的组合方式的笛卡尔积。
采用递归的方式:
1. 递归结束条件:只剩下一个数(没有符号了),存储这个区间(只有一个数,最小的区间)的结果值。
2. 递归的每一层的遍历搜索(区间的划分):每一个运算符号都划分一次
3. 递归的每一个区间结果的合并,取取笛卡尔积
那么实现代码就很简单了:
public class Solution {
public List<Integer> diffWaysToCompute(String input) {
List<Integer> list = new ArrayList<>();
if(!(input.contains("+")||input.contains("-")||input.contains("*"))) //递归到底,只剩下一个单独的数字了
list.add(Integer.valueOf(input));
for(int i=0; i<input.length(); i++){
if(input.charAt(i)=='+' || input.charAt(i)=='-' || input.charAt(i)=='*'){ //对于一个字符串需要每个负号都划分一次
String left = input.substring(0,i); //划分,为两部分(三部分)
char c = input.charAt(i);
String right = input.substring(i+1);
//对于每一次划分
List<Integer> a = diffWaysToCompute(left); //取得左边区间的结果集(怎么取的不关心)
List<Integer> b = diffWaysToCompute(right); //取得右边区间的结果集(怎么取的不关心)
for (int j : a) { //对两个结果集求笛卡尔积
for (int k : b) {
if (c == '+') {
list.add(j + k);
} else if (c == '-') {
list.add(j - k);
} else if (c == '*') {
list.add(j * k);
}
}
}
}
}
return list;
}
}