检查两个数学表达式是否相等

时间:2018-05-16 18:11:39

标签: algorithm tree

我在接受采访时遇到了一个问题。我尝试解决它但无法提出解决方案。问题是:

将帖子 第一部分:给出两个只有“+”运算符的表达式,检查给定两个表达式在数学上是否等价。 例如,“A + B + C”相当于“A +(B + C)”。

第二部分:给出两个只有“+”和“ - ”运算符的表达式,检查给定的两个表达式在数学上是否等价。 例如,“A + B-C”相当于“A - ( - B + C)”。

我的思考过程:我正在考虑用给定表达式构建表达式树并寻找某种相似性。但是我无法想出一个检查两个表达式树是否相同的好方法。

有人可以帮我这个:)提前谢谢!

3 个答案:

答案 0 :(得分:1)

只要操作是可交换的,我建议的解决方案就是分配括号操作,然后按'变量'对术语进行排序,然后在它们之间运行聚合器,你应该得到一串因子和符号。然后检查一系列因素。

答案 1 :(得分:1)

聚合变量计数,直到遇到一个左括号,将减法视为添加否定变量。递归处理子表达式。

子表达式的内容可以直接聚合到计数中,您只需要正确地考虑该符号 - 不需要为此任务创建实际的表达式树。代码中使用的TreeMap只是JDK中的有序映射实现。

代码利用了当前位置是Reader状态的一部分这一事实,因此我们可以在递归调用的结束括号之后轻松地继续解析,而无需将此信息明确地传递给调用者不知。

Java实现(未经测试):

class Expression {
   // Count for each variable name
   Map<String, Integer> counts = new TreeMap<>();

   Expression(Srring s) throws IOException {
     this(new StringReader(s));
   }

   Expression(Reader reader) throws IOException {
     int sign = 1;
     while (true) {
       int token = reader.read(); 
       switch (token) {
         case -1:  // Eof
         case ')':
           return;
         case '(':
           add(sign, new Expression(reader));
           sign = 1;
           break;
         case '+':
           break;
         case '-':
           sign = -sign;
           break;
         default:
           add(sign, String.valueOf((char) token));
           sign = 1;
           break;
       }
     }
   }

   void add(int factor, String variable) {
     int count = counts.containsKey(variable) ? counts.get(variable) : 0;
     counts.put(count + factor, variable);
   }

   void add(int sign, Expression expr) {
     for (Map.Entry<String,Integer> entry : expr.counts.entrySet()) {
       add(sign * entry.getVaue(), entry.getKey());
     }
   }

   void equals(Object o) {
     return (o instanceof Expression) 
        && ((Expression) o).counts.equals(counts);
   }

   // Not needed for the task, just added for illustration purposes.
   String toString() {
     StringBuilder sb = new StringBuilder();
     for (Map.Entry<String,Integer> entry : expr.counts.entrySet()) {
       if (sb.length() > 0) {
         sb.append(" + ");
       }
       sb.append(entry.getValue());  // count
       sb.append(entry.getKey());    // variable name
     }
     return sb.toString();
   }
 }

比较
new Expression("A+B-C").equals(new Expression("A-(-B+C)"))

P.S:添加了toString()方法以更好地说明数据结构。

应该为示例打印1A + 1B + -1C

P.P.P.P.S。:修复,简化,更好的解释。

答案 2 :(得分:0)

您可以从左到右解析表达式并将它们缩减为规范形式,以便以直接的方式进行比较;唯一的复杂因素是,当你遇到一个结束括号时,你需要知道它的相关开口括号前面是加号还是减号;你可以使用堆栈;例如:

function Dictionary() {
    this.d = [];
}
Dictionary.prototype.add = function(key, value) {
    if (!this.d.hasOwnProperty(key)) this.d[key] = value;
    else this.d[key] += value;
}
Dictionary.prototype.compare = function(other) {
    for (var key in this.d) {
        if (!other.d.hasOwnProperty(key) || other.d[key] != this.d[key]) return false;
    }
    return this.d.length == other.d.length;
}

function canonize(expression) {
    var tokens = expression.split('');
    var variables = new Dictionary();
    var sign_stack = [];
    var total_sign = 1;
    var current_sign = 1;

    for (var i in tokens) {
        switch(tokens[i]) {
            case '(' : {
                sign_stack.push(current_sign);
                total_sign *= current_sign;
                current_sign = 1;
                break;
            }
            case ')' : {
                total_sign *= sign_stack.pop();
                break;
            }
            case '+' : {
                current_sign = 1;
                break;
            }
            case '-' : {
                current_sign = -1;
                break;
            }
            case ' ' : {
                break;
            }
            default : {
                variables.add(tokens[i], current_sign * total_sign);
            }
        }
    }
    return variables;
}

var a = canonize("A + B + (A - (A + C - B) - B) - C");
var b = canonize("-C - (-A - (B + (-C)))");
document.write(a.compare(b));