Given an expression such as expression = "e + 8 - a + 5" and an evaluation map such as {"e": 1} (given in terms of evalvars = ["e"] and evalints = [1]), return a list of tokens representing the simplified expression, such as ["-1*a","14"]
An expression alternates chunks and symbols, with a space separating each chunk and symbol.
A chunk is either an expression in parentheses, a variable, or a non-negative integer.
A variable is a string of lowercase letters (not including digits.) Note that variables can be multiple letters, and note that variables never have a leading coefficient or unary operator like "2x" or "-x".
Expressions are evaluated in the usual order: brackets first, then multiplication, then addition and subtraction.
For example, expression = "1 + 2 * 3" has an answer of ["7"].
The format of the output is as follows:
For each term of free variables with a non-zero coefficient, we write the free variables within a term in sorted order lexicographically.
For example, we would never write a term like "b*a*c", only "a*b*c".
Terms have degrees equal to the number of free variables being multiplied, counting multiplicity. We write the largest degree terms of our answer first, breaking ties by lexicographic order ignoring the leading coefficient of the term.
For example, "a*a*b*c" has degree 4.
The leading coefficient of the term is placed directly to the left with an asterisk separating it from the variables (if they exist.) A leading coefficient of 1 is still printed.
An example of a well-formatted answer is ["-2*a*a*a", "3*a*a*b", "3*b*b", "4*a", "5*c", "-6"].
Terms (including constant terms) with coefficient 0 are not included.
For example, an expression of "0" has an output of [].
Note: You may assume that the given expression is always valid. All intermediate results will be in the range of [-2^31, 2^31 - 1].
Solutions for this version, however, require some extra effort apart from the general structure in Basic Calculator 3.
Due to the presence of variables (free variables, to be exact), partial results at each calculation step might be expressions rather than pure numbers. We need a structure to properly represent partial results.
We should design a structure to easily handle operations like addition, subtraction, and multiplication. Here, each expression is shown as a collection of mappings between terms and their coefficients, where each term is a list of free variables in lexicographic order. Here are two examples:
"2 * a * b - d * c": This expression has two terms: ["a", "b"] with a coefficient of 2 and ["c", "d"] with a coefficient of -1. Thus, we represent it as ["a", "b"] --> 2 and ["c", "d"] --> -1.
"4": This expression has a single term with zero free variables, represented as []. The coefficient is 4, giving us the mapping [] --> 4. Generally, for any expression consisting of a pure number, we have the mapping [] --> num.
The Term and Expression classes defined below further clarify the details.
See below for a detailed definition of the Term and Expression classes.
Term class:
1
2
3
4
5
6
7
8
9
10
// doesnt contain coeffprivatestaticclassTermimplements Comparable<Term> {
List<String> vars;
staticfinal Term C =new Term(Arrays.asList()); // this is the term for pure numbers Term(List<String> vars) {
this.vars= vars;
}
// code removed below for clarity, complete code available in the solution below}
The Term class allows for term comparison based on their degrees and generates custom string representations.
The Expression class facilitates the addition of new terms to the existing mapping.
Addition of two expressions involves merging all mappings from the second expression into the first, combining the coefficients of identical terms when possible.
1
2
3
4
5
6
7
private Expression addition(Expression expression1, Expression expression2, int sign) {
for (Map.Entry<Term, Integer> e : expression2.terms.entrySet()) {
expression1.addTerm(e.getKey(), sign * e.getValue());
}
return expression1;
}
Subtraction of two expressions is achieved by first negating the coefficients of the second expression’s terms and then adding them to the first expression (effectively, this can be combined with the addition by using the addition function with a sign of -1).
Multiplication of two expressions involves combining each term from the first expression with every term from the second expression, including their coefficients.
private Expression multiplication(Expression expression1, Expression expression2) {
Expression res =new Expression(Term.C, 0);
for (Map.Entry<Term, Integer> e1 : expression1.terms.entrySet()) {
for (Map.Entry<Term, Integer> e2 : expression2.terms.entrySet()) {
res.addTerm(merge(e1.getKey(), e2.getKey()), e1.getValue() * e2.getValue());
}
}
return res;
}
private Term merge(Term term1, Term term2) {
List<String> vars =new ArrayList<>();
vars.addAll(term1.vars);
vars.addAll(term2.vars);
Collections.sort(vars);
returnnew Term(vars);
}
Finally, to match the required output format, we have a function that converts the mappings in the result expression to a list of strings. Each string consists of the coefficient and the term joined by the * operator. Terms with a 0 coefficient are excluded, and terms without free variables are represented by numbers alone.
Regarding complexity, the nominal runtime complexity of this solution is similar to the recursive approach for Basic Calculator III, which is O(n^2). By using stacks for the simulation, the nominal time complexity can be reduced to O(n)—left as an exercise.
The term “nominal” is used because the complexity analysis assumes constant time for addition, subtraction, and multiplication operations on expressions, as with pure numbers. This assumption is not always valid since the number of terms can grow exponentially (e.g., (a + b) * (c + d) * (e + f) * ...). Nevertheless, this solution should be effective for general test cases.
⏰ Time complexity: O(n * m^2) where n is the length of the expression and m is the number of distinct terms. The dominant factor is merging terms during multiplication.
🧺 Space complexity: O(n + m) due to storing terms and expression objects.