You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用Java代码动态化简代数表达式(含括号与符号处理)

Java实现代数表达式去括号并展开符号

我之前做类似需求的时候,核心思路就是递归处理嵌套括号 + 跟踪当前符号上下文,其实逻辑理清了就很简单。下面给你一步步拆解实现思路和可运行的代码:

核心思路

我们需要维护一个「当前符号上下文」,比如当前处于正号还是负号的作用域内。遇到括号时,根据括号前的符号,把这个上下文传递给括号内的内容,递归处理括号里的表达式,处理完后再把结果拼回来。

举个例子:-((a-b)+(b-d)),括号前是负号,所以括号内的每一项符号都要反转——(a-b)变成-a+b(b-d)变成-b+d,最后拼起来就是-a+b-b+d

具体实现步骤

  1. 预处理表达式:先把所有空格去掉,避免干扰遍历
  2. 递归遍历 + 符号跟踪:用递归函数处理每个部分,维护当前的符号(用1表示正,-1表示负)
  3. 处理不同字符
    • 遇到+/-:更新当前项的临时符号(结合上下文符号)
    • 遇到(:找到匹配的),递归处理括号内内容,用括号前的符号作为递归的上下文符号
    • 遇到变量/数字:收集完整的项,根据当前符号添加到结果中

完整Java代码示例

import java.util.Stack;

public class ExpressionUnwrapper {

    public static void main(String[] args) {
        String inputExpr = "a+(b-c+d)-((a-b)+(b-d))";
        String unwrappedExpr = unwrapParentheses(inputExpr);
        System.out.println("原始表达式: " + inputExpr);
        System.out.println("展开后表达式: " + unwrappedExpr);
        // 输出结果: a+b-c+d-a+b-b+d
    }

    // 对外暴露的入口方法
    public static String unwrapParentheses(String expression) {
        // 先清除所有空格
        String cleanExpr = expression.replaceAll("\\s+", "");
        // 初始符号为正,处理整个表达式
        return processSegment(cleanExpr, 0, cleanExpr.length(), 1);
    }

    // 递归处理表达式片段的核心方法
    private static String processSegment(String expr, int startIdx, int endIdx, int currentContextSign) {
        StringBuilder result = new StringBuilder();
        int currentTermSign = currentContextSign; // 当前项的符号,初始和上下文一致

        int i = startIdx;
        while (i < endIdx) {
            char currentChar = expr.charAt(i);

            if (currentChar == '+' || currentChar == '-') {
                // 根据当前上下文符号,计算当前项的实际符号
                currentTermSign = currentContextSign * (currentChar == '+' ? 1 : -1);
                i++;
            } else if (currentChar == '(') {
                // 找到匹配的右括号位置
                int matchingCloseIdx = findMatchingClosingParen(expr, i);
                // 递归处理括号内的内容,传入当前项的符号作为新的上下文
                String innerResult = processSegment(expr, i + 1, matchingCloseIdx, currentTermSign);
                result.append(innerResult);
                // 跳过整个括号
                i = matchingCloseIdx + 1;
                // 处理完括号后,重置当前项符号为上下文符号
                currentTermSign = currentContextSign;
            } else if (currentChar == ')') {
                // 递归到这里说明已经处理完括号内内容,直接跳出
                break;
            } else {
                // 收集完整的变量/数字项(支持多字符变量或数字)
                StringBuilder term = new StringBuilder();
                while (i < endIdx && (Character.isLetterOrDigit(expr.charAt(i)))) {
                    term.append(expr.charAt(i));
                    i++;
                }
                // 根据当前项符号添加前缀
                if (currentTermSign == -1) {
                    result.append('-');
                } else if (result.length() > 0) {
                    // 不是第一个项且符号为正,需要添加+号
                    result.append('+');
                }
                result.append(term);
                // 重置当前项符号为上下文符号
                currentTermSign = currentContextSign;
            }
        }

        return result.toString();
    }

    // 辅助方法:找到与当前左括号匹配的右括号位置
    private static int findMatchingClosingParen(String expr, int openParenIdx) {
        Stack<Character> parenStack = new Stack<>();
        parenStack.push(expr.charAt(openParenIdx));
        int i = openParenIdx + 1;

        while (!parenStack.isEmpty() && i < expr.length()) {
            char c = expr.charAt(i);
            if (c == '(') {
                parenStack.push(c);
            } else if (c == ')') {
                parenStack.pop();
            }
            i++;
        }
        // 返回匹配的右括号索引
        return i - 1;
    }
}

关键细节说明

  • 括号匹配:用栈来处理嵌套括号,确保不管多少层嵌套都能正确找到对应的右括号
  • 符号传递:递归时把括号前的符号作为新的上下文,这样括号内所有项都会自动应用这个符号,不需要手动逐个反转
  • 项的收集:支持多字符变量(比如abc)或数字(比如123),如果需要处理带系数的项(比如2a),可以直接扩展这里的收集逻辑

扩展方向

如果后续需要合并同类项(比如把a-a+b-b化简为0),可以在展开表达式后,用HashMap<String, Integer>统计每个变量的系数,然后遍历哈希表生成最终的化简表达式。

内容的提问来源于stack exchange,提问作者Jeevitha

火山引擎 最新活动