Spreadsheet Formula Dependencies
Problem statement
Maintain an initially empty in-memory spreadsheet. Each cell holds either an integer or a formula referring to other cells. Process operations in order and return one string for every operation.
For this exercise, each formula is one binary expression. Its left and right operands are independently either a cell identifier or an integer literal. Formulas can be nested through cell references.
["SET", cell, value]replaces the cell with the integervalueand returns"OK".["FORMULA", cell, left, operator, right]proposes replacing the cell withleft operator right. The operator is+,-,*, or/. Accept the replacement and return"OK"unless it introduces a direct or indirect circular reference. In that case, return"CYCLE"and leave the spreadsheet completely unchanged.["GET", cell]returns the cell's current value as a decimal string. A cell that has never been assigned has value0. Values must reflect every earlier accepted update, including updates to indirect dependencies.
Arithmetic is integer arithmetic. Division truncates toward zero. Division by zero, or a reference to a cell whose evaluation encounters division by zero, makes that evaluation return "ERROR". Such a formula may be stored successfully; the error is reported when its value is read. A later update can repair it.
Using the same cell more than once in a formula is legal and is not itself a cycle. Replacing a formula removes its old dependency relationships. Rejected updates must not change definitions or cached values.
In a read-heavy workload, how can per-query memoization be improved with a persistent cache and reverse dependencies? Explain which cached cells must be invalidated after an accepted update and how overwriting a formula changes the dependency graph.
Function
runSpreadsheet(operations: String[][]) → String[]Examples
Example 1
operations = [["SET","A1","3"],["FORMULA","B1","A1","*","2"],["GET","B1"],["SET","A1","5"],["GET","B1"]]return = ["OK","OK","6","OK","10"]The formula in B1 doubles the current value of A1. Its second read must use the updated value rather than a stale cached result.
Example 2
operations = [["FORMULA","A1","B1","+","B1"],["GET","A1"],["SET","B1","4"],["GET","A1"],["FORMULA","B1","A1","+","1"],["GET","B1"]]return = ["OK","0","OK","8","CYCLE","4"]Repeating B1 in the first formula is legal. Replacing B1 with a reference to A1 would create a cycle, so that update is rejected and B1 remains 4.
Example 3
operations = [["SET","Z1","0"],["FORMULA","A1","7","/","Z1"],["GET","A1"],["SET","Z1","2"],["GET","A1"],["FORMULA","B1","-7","/","2"],["GET","B1"]]return = ["OK","OK","ERROR","OK","3","OK","-3"]The stored formula initially divides by zero. Updating its denominator repairs it. Both positive and negative division truncate toward zero.
Constraints
0 <= operations.length <= 256.- At most
64distinct cell identifiers appear anywhere in the operations. Each matches[A-Z][A-Z0-9]{0,3}. - Every operation has exactly the form described above. Numeric strings are canonical decimal integers, with an optional leading minus sign and no leading zeros except
0. Their absolute values are at most10^6. - At every step, each arithmetic subexpression without a division-by-zero dependency has its integer value in
[-10^9, 10^9]. - There are no parentheses or extra operators inside an operand; compose larger expressions by referencing formula cells. All identifiers and operators are case-sensitive.