FastPrepSpreadsheet Formula Dependencies

Spreadsheet Formula Dependencies

Citadel logoCitadel● HardFULLTIMEPHONE SCREEN
Learn

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 integer value and returns "OK".
  • ["FORMULA", cell, left, operator, right] proposes replacing the cell with left 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 value 0. 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 64 distinct 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 most 10^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.

More Citadel problems

See Citadel hiring insights
public String[] runSpreadsheet(String[][] operations) {
    // Write your code here.
}
operations[["SET","A1","3"],["FORMULA","B1","A1","*","2"],["GET","B1"],["SET","A1","5"],["GET","B1"]]
expected["OK", "OK", "6", "OK", "10"]
Checking account…