我在接受采访时遇到了一个问题。我尝试解决它但无法提出解决方案。问题是:
将帖子 第一部分:给出两个只有“+”运算符的表达式,检查给定两个表达式在数学上是否等价。 例如,“A + B + C”相当于“A +(B + C)”。
第二部分:给出两个只有“+”和“ - ”运算符的表达式,检查给定的两个表达式在数学上是否等价。 例如,“A + B-C”相当于“A - ( - B + C)”。
我的思考过程:我正在考虑用给定表达式构建表达式树并寻找某种相似性。但是我无法想出一个检查两个表达式树是否相同的好方法。
有人可以帮我这个:)提前谢谢!
答案 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));