https://leetcode-cn.com/problems/different-ways-to-add-parentheses/
给你一个由数字和运算符组成的字符串 expression ,按不同优先级组合数字和运算符,计算并返回所有可能组合的结果。你可以 按任意顺序 返回答案。
**输入:**expression = “2-1-1” 输出:[0,2] 解释: ((2-1)-1) = 0 (2-(1-1)) = 2
输入:expression = “23-45”
输出:[-34,-14,-10,-10,10]
解释:
(2*(3-(45))) = -34
((23)-(45)) = -14
((2(3-4))5) = -10
(2((3-4)5)) = -10
(((23)-4)*5) = 10
条件
1 <= expression.length <= 20
expression 由数字和算符 ‘+’、‘-’ 和 ‘*’ 组成。
输入表达式中的所有整数值在范围 [0, 99]
这道题目是出现在动态规划中等难度区的,拿到这道题,我首先观察到表达式的长度最长为20,而通过规律,我发现:
1x2-3+4 就算是所有的数字都是一位(保证符号尽可能多),符号也最多只出现10个左右。同时,大括号这个操作本质上来说,就是确定符号执行的先后顺序,所以,我的解决方案也出来了:枚举每一种符号执行的先后顺序,然后求出对应的值即可,这里有个值得注意的点就是对于**((23)-(45))**这种形式,可能多个符号执行顺序得到的字符串都是这个,比如132和312,都能画出上面这个形式,所以这里还需要使用一个集合去重。
那么,首先需要做的就是要生成符号执行序列,这一步就使用到了递归生成全排列的思路:
public static void swap(char[] c, int i, int j) {
char tmp;
tmp = c[i];
c[i] = c[j];
c[j] = tmp;
}
public static void printAll(char[] x, List<String> cache, int index) {
if (index == x.length - 1) {
cache.add(String.valueOf(x));
} else {
for (int i = index; i < x.length; i++) {
swap(x, i, index);
printAll(x, cache, index + 1);
swap(x, index, i);
}
}
}
然后实现根据执行顺序生成对应的括号表达式
public static String changeExpression(String expression, int index) {
int n = expression.length();
int cnt = 0;
String newStr = expression;
for (int i = 0; i < n; i++) {
if (newStr.charAt(i) == '+' || newStr.charAt(i) == '-' || newStr.charAt(i) == '*') {
cnt++;
if (cnt == index) {
// TODO: 2022/4/29 在左和有添加括号
int cntRight = 0;
int flagRight = 0;
int newN = newStr.length();
for (int j = i + 1; j < newN; j++) {
if (newStr.charAt(j) == ')') {
flagRight = 1;
cntRight--;
}
if (newStr.charAt(j) == '(') {
flagRight = 1;
cntRight++;
}
if (cntRight == 0) {
if (flagRight == 1) {
// TODO: 2022/4/29 进入过括号区域
newStr = newStr.substring(0, j + 1) + ")" + ((j + 1 < newN) ? newStr.substring(j + 1) : "");
break;
} else {
// TODO: 2022/4/29 没有进入到有括号的区域
if (j + 1 < newN) {
if (newStr.charAt(j + 1) >= '0' && newStr.charAt(j + 1) <= '9') {
newStr = newStr.substring(0, j + 2) + ")" + ((j + 2 < newN) ? newStr.substring(j + 2) : "");
break;
} else {
newStr = newStr.substring(0, j + 1) + ")" + ((j + 1 < newN) ? newStr.substring(j + 1) : "");
break;
}
} else {
newStr = newStr.substring(0, j + 1) + ")" + ((j + 1 < newN) ? newStr.substring(j + 1) : "");
break;
}
}
}
}
int cntLeft = 0;
int flagLeft = 0;
newN = newStr.length();
for (int j = i - 1; j >= 0; j--) {
if (newStr.charAt(j) == ')') {
cntLeft++;
flagLeft = 1;
}
if (newStr.charAt(j) == '(') {
cntLeft--;
flagLeft = 1;
}
if (cntLeft == 0) {
if (flagLeft == 1) {
newStr = (j - 1 > 0 ? newStr.substring(0, j) : "") + "(" + newStr.substring(j);
break;
} else {
if (j - 1 >= 0) {
if (newStr.charAt(j - 1) >= '0' && newStr.charAt(j - 1) <= '9') {
newStr = (j - 2 > 0 ? newStr.substring(0, j - 1) : "") + "(" + newStr.substring(j - 1);
break;
} else {
newStr = (j - 1 > 0 ? newStr.substring(0, j) : "") + "(" + newStr.substring(j);
break;
}
} else {
newStr = (j - 2 > 0 ? newStr.substring(0, j) : "") + "(" + newStr.substring(j);
break;
}
}
}
}
}
}
}
return newStr;
}
然后使用循环调用,即可实现对一整个序列的变换
for (int i = 0; i < m; i++) {
int tmp = y.charAt(i) - '0';
aa = changeExpression(aa, tmp);
}
最后,我们只需要计算表达式的值即可
public static boolean isValid2(String s) {
Stack<Character> a = new Stack<>();
int n = s.length();
for (int i = 0; i < n; i++) {
if (s.charAt(i) == '(' || s.charAt(i) == ')'){
a.push(s.charAt(i));
}
}
Stack<Character> b = new Stack<>();
while (!a.empty()) {
Character x = a.pop();
if (b.empty()) {
b.push(x);
continue;
}
Character y = b.pop();
if ((x == '(' && y == ')')) {
continue;
} else {
b.push(y);
b.push(x);
}
}
if (a.empty() && b.empty()) {
return true;
}
return false;
}
public static Integer getAns(String expression) {
try {
Integer ans = Integer.parseInt(expression);
return ans;
} catch (Exception e) {
}
int n = expression.length();
if (!expression.contains("(") && !expression.contains(")")) {
int flag1 = 0;
int opeFlag = 0;
char ope = '0';
int flag2 = 0;
String param1 = "";
String param2 = "";
for (int i = 0; i < n; i++) {
char a = expression.charAt(i);
if (flag1 == 0) {
if (a == '-') {
flag1 = 1;
param1 = param1 + "-";
}else {
param1 = param1 + a;
flag1 = 1;
}
} else {
if (opeFlag == 0) {
if (a == '-' || a == '+' || a == '*') {
opeFlag = 1;
ope = a;
} else {
param1 = param1 + a;
}
} else {
param2 = param2 + a;
}
}
}
Integer ans = 0;
if (ope == '+') {
ans = Integer.parseInt(param1) + Integer.parseInt(param2);
}
if (ope == '-') {
ans = Integer.parseInt(param1) - Integer.parseInt(param2);
}
if (ope == '*') {
ans = Integer.parseInt(param1) * Integer.parseInt(param2);
}
return ans;
}
if (expression.charAt(0) == '(' && expression.charAt(n - 1) == ')') {
// TODO: 2022/4/29 考虑去掉最外层括号
String newStr = expression.substring(1, n - 1);
if (isValid2(newStr)){
return getAns(newStr);
}
}
int[] dp = new int[n];
for (int i = 0; i < n; i++) {
char a = expression.charAt(i);
if (i == 0) {
if (a == '(') {
dp[0] = 1;
}
} else {
if (a == '(') {
dp[i] = dp[i - 1] + 1;
} else if (a == ')') {
dp[i] = dp[i - 1] - 1;
} else {
dp[i] = dp[i - 1];
}
}
if (a == '+' || a == '-' || a == '*') {
if (dp[i] == 0) {
if (a == '+') {
return getAns(expression.substring(0, i)) + getAns(expression.substring(i + 1));
} else if (a == '-') {
return getAns(expression.substring(0, i)) - getAns(expression.substring(i + 1));
} else if (a == '*') {
return getAns(expression.substring(0, i)) * getAns(expression.substring(i + 1));
}
}
}
}
return 0;
}
这段代码有点词法解析器的意思。
最后,实现调用函数即可
public List<Integer> diffWaysToCompute(String expression) {
int n = expression.length();
int fuN = 0;
for (int i = 0; i < n; i++) {
if (expression.charAt(i) == '+' || expression.charAt(i) == '-' || expression.charAt(i) == '*') {
fuN++;
}
}
if (fuN == 0){
fuN = 1;
}
char[] x = new char[fuN];
for (int i = 0; i < fuN; i++) {
x[i] = Integer.toString(i + 1).charAt(0);
}
List<String> ans = new ArrayList<>();
printAll(x, ans, 0);
Set<String> res = new HashSet<>();
for (String y : ans) {
int m = y.length();
String aa = expression + "";
for (int i = 0; i < m; i++) {
int tmp = y.charAt(i) - '0';
aa = changeExpression(aa, tmp);
}
res.add(aa);
}
List<Integer> ans123 = new ArrayList<>();
for (String xx : res) {
Integer aaa = getAns(xx);
ans123.add(aaa);
}
return ans123;
}