为运算表达式设计优先级

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
((2
3)-(45)) = -14
((2
(3-4))5) = -10
(2
((3-4)5)) = -10
(((2
3)-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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海燕技术栈

你的鼓励我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值