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"]
"2x"
or "-x"
.Expressions are evaluated in the usual order: brackets first, then multiplication, then addition and subtraction.
expression = "1 + 2 * 3"
has an answer of ["7"]
.The format of the output is as follows:
"b*a*c"
, only "a*b*c"
."a*a*b*c"
has degree 4
.["-2*a*a*a", "3*a*a*b", "3*b*b", "4*a", "5*c", "-6"]
.0
are not included.
"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 [-231, 231 - 1]
.
Example 1:
Input: expression = "e + 8 - a + 5", evalvars = ["e"], evalints = [1] Output: ["-1*a","14"]
Example 2:
Input: expression = "e - 8 + temperature - pressure", evalvars = ["e", "temperature"], evalints = [1, 12] Output: ["-1*pressure","5"]
Example 3:
Input: expression = "(e + 8) * (e - 8)", evalvars = [], evalints = [] Output: ["1*e*e","-64"]
Constraints:
1 <= expression.length <= 250
expression
consists of lowercase English letters, digits, '+'
, '-'
, '*'
, '('
, ')'
, ' '
.expression
does not contain any leading or trailing spaces.expression
are separated by a single space.0 <= evalvars.length <= 100
1 <= evalvars[i].length <= 20
evalvars[i]
consists of lowercase English letters.evalints.length == evalvars.length
-100 <= evalints[i] <= 100
This problem requires evaluating an arithmetic expression containing variables and then simplifying the resulting polynomial expression. The solution involves several key steps:
1. Parsing the Expression:
The input expression is a string. We need to parse it into a tree-like structure to represent the order of operations. This can be done recursively using a stack-based approach or a recursive descent parser. The parsing process will handle parentheses, operators (+, -, *), variables, and numerical constants.
2. Evaluating the Expression (with variable substitutions):
Once parsed, the expression can be evaluated. If evalvars
and evalints
are provided, substitute the variable values before evaluation. This step will simplify the expression numerically wherever possible.
3. Polynomial Simplification:
After evaluation (or if no substitutions are provided), the expression needs to be simplified into a canonical polynomial form. This involves collecting like terms and representing the result as a list of terms, each with a coefficient and a sorted product of variables. This is the most complex part of the problem. A common approach is to use a hashmap (dictionary in Python) to store the coefficients of each variable combination.
4. Output Formatting:
Finally, format the simplified polynomial into the specified output format. The terms must be sorted according to the specified rules (degree then lexicographically).
Time Complexity Analysis:
The time complexity depends on several factors:
Parsing: The time complexity of parsing the expression is O(N), where N is the length of the expression string, assuming a straightforward recursive descent parser or stack-based approach.
Evaluation: Evaluating the expression with substitutions can also be O(N) in the worst case.
Polynomial Simplification: The most computationally expensive part. The worst-case scenario is when we have many different variable combinations. Building the hashmap and then sorting the terms can dominate. In the worst case, the number of unique terms could be exponential in the number of distinct variables. In more practical cases (expressions with a reasonable number of variables and terms), this step will likely be closer to O(M log M), where M is the number of unique terms generated after simplification (M ≤ N).
Output Formatting: Sorting the terms (to meet output specifications) is O(M log M).
Therefore, the overall time complexity is dominated by the polynomial simplification and sorting steps, making the upper bound O(M log M), where M is the number of unique terms in the simplified polynomial. However, in the worst case (a very large number of unique variable combinations), it could be considered exponential.
Space Complexity Analysis:
The space complexity is largely determined by the size of the intermediate data structures used:
Parsing: The recursive call stack during parsing can consume O(N) space in the worst case (deeply nested parentheses).
Evaluation: The space required for storing intermediate results is O(N).
Polynomial Simplification: The hashmap to store coefficients for each variable combination can consume significant space. In the worst case, the size is proportional to the number of unique terms, potentially exponential in the number of distinct variables, although often much smaller in practice.
Therefore, the overall space complexity is dominated by the hashmap used for polynomial simplification. In the worst case, it is potentially exponential, but in practical cases, it is often closer to O(M), where M is the number of unique terms.
Note: Providing specific code in multiple languages would make the response extremely long. The core algorithms are language-agnostic. The complexity analysis is the most important aspect to understand when tackling this problem. The implementation details would depend on the chosen data structures and parsing method (recursive descent, stack-based, etc.). Libraries can simplify some parts (e.g., using a dedicated polynomial library), but the core complexity remains.