Approach
Sorting and greedy selection
For Basic Calculator IV, the implementation first exposes a useful order, then scans that order while making locally justified choices.
- Choose the key that reveals the greedy or grouping structure.
- Sort the relevant records by that key.
- Scan in order, maintaining the invariant that makes each local choice safe.
Code notes
- 147 lines of Python from the credited upstream file 770.py.
- The implementation visibly relies on sequence storage, hash lookup.
- No explicit loop blocks detected.
Complexity
Sorting is typically the dominant term unless the subsequent scan uses a more expensive nested operation.
Check the problem constraints before deciding whether this complexity will pass.
Use this to learn the idea, then write your own version.
1class Poly:2 def __init__(self, term: str = None, coef: int = None):3 if term and coef:4 self.terms = collections.Counter({term: coef})5 else:6 self.terms = collections.Counter()7 8 def __add__(self, other):9 for term, coef in other.terms.items():10 self.terms[term] += coef11 return self12 13 def __sub__(self, other):14 for term, coef in other.terms.items():15 self.terms[term] -= coef16 return self17 18 def __mul__(self, other):19 res = Poly()20 for a, aCoef in self.terms.items():21 for b, bCoef in other.terms.items():22 res.terms[self._merge(a, b)] += aCoef * bCoef23 return res24 25 26 27 28 29 30 31 def toList(self) -> list[str]:32 for term in list(self.terms.keys()):33 if not self.terms[term]:34 del self.terms[term]35 36 def cmp(term: str) -> tuple:37 38 if term == '1':39 return (0,)40 var = term.split('*')41 42 43 return (-len(var), term)44 45 def concat(term: str) -> str:46 if term == '1':47 return str(self.terms[term])48 return str(self.terms[term]) + '*' + term49 50 terms = list(self.terms.keys())51 terms.sort(key=cmp)52 return [concat(term) for term in terms]53 54 def _merge(self, a: str, b: str) -> str:55 if a == '1':56 return b57 if b == '1':58 return a59 res = []60 A = a.split('*')61 B = b.split('*')62 i = 0 63 j = 0 64 while i < len(A) and j < len(B):65 if A[i] < B[j]:66 res.append(A[i])67 i += 168 else:69 res.append(B[j])70 j += 171 return '*'.join(res + A[i:] + B[j:])72 73 74class Solution:75 def basicCalculatorIV(76 self,77 expression: str,78 evalvars: list[str],79 evalints: list[int],80 ) -> list[str]:81 tokens = list(self._getTokens(expression))82 evalMap = {a: b for a, b in zip(evalvars, evalints)}83 84 for i, token in enumerate(tokens):85 if token in evalMap:86 tokens[i] = str(evalMap[token])87 88 postfix = self._infixToPostfix(tokens)89 return self._evaluate(postfix).toList()90 91 def _getTokens(self, s: str) -> Iterator[str]:92 i = 093 for j, c in enumerate(s):94 if c == ' ':95 if i < j:96 yield s[i:j]97 i = j + 198 elif c in '()+-*':99 if i < j:100 yield s[i:j]101 yield c102 i = j + 1103 if i < len(s):104 yield s[i:]105 106 def _infixToPostfix(self, tokens: list[str]) -> list[str]:107 postfix = []108 ops = []109 110 def precedes(prevOp: str, currOp: str) -> bool:111 if prevOp == '(':112 return False113 return prevOp == '*' or currOp in '+-'114 115 for token in tokens:116 if token == '(':117 ops.append(token)118 elif token == ')':119 while ops[-1] != '(':120 postfix.append(ops.pop())121 ops.pop()122 elif token in '+-*': 123 while ops and precedes(ops[-1], token):124 postfix.append(ops.pop())125 ops.append(token)126 else: 127 postfix.append(token)128 return postfix + ops[::-1]129 130 def _evaluate(self, postfix: list[str]) -> Poly:131 polys: list[Poly] = []132 for token in postfix:133 if token in '+-*':134 b = polys.pop()135 a = polys.pop()136 if token == '+':137 polys.append(a + b)138 elif token == '-':139 polys.append(a - b)140 else: 141 polys.append(a * b)142 elif token.lstrip('-').isnumeric():143 polys.append(Poly("1", int(token)))144 else:145 polys.append(Poly(token, 1))146 return polys[0]147