PracHub
QuestionsCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates a candidate's ability to design a stateful data structure that models dependency relationships and lazily propagates updates, a common theme in coding and algorithms interviews. It tests skills in graph traversal, cycle detection, and choosing between eager versus lazy evaluation to optimize for a given read/write workload. This is a practical, implementation-level problem assessing system design intuition within a single class rather than pure theoretical knowledge.

  • medium
  • Harvey
  • Coding & Algorithms
  • Software Engineer

Spreadsheet Formula Engine with Cycle Detection

Company: Harvey

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Technical Screen

Implement a `Spreadsheet` class that supports cells holding either a literal integer or a **formula** that references other cells. This is the core of a spreadsheet calculation engine: when a cell that others depend on changes, every dependent cell must reflect the new value. ## API Implement the following two methods: - `set_cell(cell_id: str, value)` — assign `value` to the cell identified by `cell_id`. `value` is either: - an **integer** (the cell stores that literal), or - a **formula string** of the form `"=<term>(+<term>)*"`, where each `<term>` is either a non-negative integer literal or a cell reference (e.g. `"=A1+B2+10"`). The formula's value is the sum of its terms, with each cell reference resolved to that cell's current value. - `get_cell(cell_id: str) -> int` — return the current integer value of the cell. If a cell has never been set, its value is `0`. A formula always reflects the **latest** values of the cells it references. For example, if `A3 = "=A1+A2"` and `A1` is later changed, a subsequent `get_cell("A3")` must use the new `A1`. Updates propagate transitively (a formula may reference a cell that is itself a formula). ## Cell IDs and formula syntax - A cell id is one or more uppercase letters followed by one or more digits: `A1`, `B2`, `AA10`. - Cell references inside a formula use the same format. - Terms in a formula are separated by `+` with no spaces. Each term is either a non-negative integer (e.g. `10`) or a cell reference (e.g. `B2`). You may assume every formula passed in is syntactically valid. ## Cyclic dependencies A `set_cell` call that would introduce a **dependency cycle** (a cell that, directly or transitively, depends on itself) is invalid. When this happens, raise a `ValueError` and leave the spreadsheet **unchanged** (the offending assignment must not take effect, and all previously stored cells keep their values). ## Performance note In the target workload, `set_cell` is called far more often than `get_cell`. Your design should make writes cheap and is free to defer formula evaluation until a value is actually read. ## Example ```text s = Spreadsheet() s.set_cell("A1", 5) s.set_cell("A2", 10) s.set_cell("A3", "=A1+A2") # A3 depends on A1 and A2 s.get_cell("A3") # -> 15 s.set_cell("A1", 7) # update A1 s.get_cell("A3") # -> 17 (reflects the new A1) s.set_cell("A4", "=A3+3") s.get_cell("A4") # -> 20 s.get_cell("B9") # -> 0 (never set) s.set_cell("A1", "=A4") # cycle: A1 -> A4 -> A3 -> A1 => raises ValueError s.get_cell("A1") # -> 7 (unchanged after the rejected write) ``` ## Constraints - At most $10^4$ distinct cells. - At most $10^5$ total `set_cell` / `get_cell` calls. - Every integer value and every evaluated cell value fits in a signed 64-bit integer. - Formula references may point to cells that have not been set yet; treat those as `0` until they are.

Quick Answer: This question evaluates a candidate's ability to design a stateful data structure that models dependency relationships and lazily propagates updates, a common theme in coding and algorithms interviews. It tests skills in graph traversal, cycle detection, and choosing between eager versus lazy evaluation to optimize for a given read/write workload. This is a practical, implementation-level problem assessing system design intuition within a single class rather than pure theoretical knowledge.

Implement a `Spreadsheet` calculation engine whose cells hold either a literal integer or a **formula** that references other cells, and expose it through a `solution(operations, args)` driver. ## Cell semantics - `set_cell(cell_id, value)` assigns `value` to a cell. `value` is either an **integer** literal, or a **formula string** `"=<term>(+<term>)*"` where each term is a non-negative integer literal or a cell reference (e.g. `"=A1+B2+10"`). A formula's value is the sum of its terms with each reference resolved to that cell's *current* value. - `get_cell(cell_id)` returns the cell's current integer value; a cell that was never set is `0`. - Formulas always reflect the **latest** values of the cells they reference, and updates propagate transitively (a formula may reference another formula cell). Because writes vastly outnumber reads in the target workload, keep `set_cell` cheap and defer formula evaluation to read time (lazy evaluation). - A `set_cell` that would introduce a **dependency cycle** (a cell that directly or transitively depends on itself) is invalid: raise a `ValueError` and leave the spreadsheet completely unchanged. Cell ids are one or more uppercase letters followed by one or more digits (`A1`, `B2`, `AA10`); references use the same format. Assume every formula is syntactically valid. ## Console I/O contract You are given two parallel arrays: - `operations[i]` is one of `"Spreadsheet"`, `"set_cell"`, or `"get_cell"`. - `args[i]` holds that call's arguments: `[]` for the constructor, `[cell_id, value]` for `set_cell`, `[cell_id]` for `get_cell`. Return a list with one entry per operation: - `None` for the constructor and for a successful `set_cell`, - the integer value for `get_cell`, - the string `"ValueError"` when a `set_cell` is rejected because it would form a cycle. ## Example ```text operations = ["Spreadsheet","set_cell","set_cell","set_cell","get_cell","set_cell","get_cell","set_cell","get_cell","get_cell","set_cell","get_cell"] args = [[], ["A1",5], ["A2",10], ["A3","=A1+A2"], ["A3"], ["A1",7], ["A3"], ["A4","=A3+3"], ["A4"], ["B9"], ["A1","=A4"], ["A1"]] # -> [None, None, None, None, 15, None, 17, None, 20, 0, "ValueError", 7] ``` `A3` reflects A1 both before (15) and after (17) A1 changes; `A4=A3+3=20`; unset `B9` is 0; the write `A1="=A4"` closes the cycle A1->A4->A3->A1 and is rejected (ValueError), leaving A1 at 7.

Constraints

  • At most 10^4 distinct cells.
  • At most 10^5 total set_cell / get_cell calls.
  • Every integer value and every evaluated cell value fits in a signed 64-bit integer.
  • Cell ids are one or more uppercase letters followed by one or more digits (A1, B2, AA10).
  • Formula terms are separated by '+' with no spaces; each term is a non-negative integer or a cell reference.
  • Formula references may point to cells that have not been set yet; treat those as 0.
  • Every formula passed in is syntactically valid.

Examples

Input: (['Spreadsheet','set_cell','set_cell','set_cell','get_cell','set_cell','get_cell','set_cell','get_cell','get_cell','set_cell','get_cell'], [[], ['A1',5], ['A2',10], ['A3','=A1+A2'], ['A3'], ['A1',7], ['A3'], ['A4','=A3+3'], ['A4'], ['B9'], ['A1','=A4'], ['A1']])

Expected Output: [None, None, None, None, 15, None, 17, None, 20, 0, 'ValueError', 7]

Explanation: Full walkthrough from the prompt: lazy formula eval reflects the latest A1 (15 then 17 after A1->7); A4=A3+3=20; unset B9=0; the cyclic write A1=A4 raises ValueError and leaves A1 at 7.

Input: (['Spreadsheet','set_cell','get_cell','set_cell','get_cell','set_cell','get_cell'], [[], ['X1','=X1'], ['X1'], ['X1','=5+10'], ['X1'], ['Y2','=B9+5'], ['Y2']])

Expected Output: [None, 'ValueError', 0, None, 15, None, 5]

Explanation: Self-reference X1='=X1' is an immediate cycle (ValueError, X1 stays unset -> 0). Pure-literal formula '=5+10'=15. '=B9+5' references unset B9 (treated as 0) -> 5.

Input: (['Spreadsheet','set_cell','set_cell','get_cell','set_cell','get_cell','set_cell','get_cell'], [[], ['A1',10], ['A2','=A1+1'], ['A2'], ['A2',100], ['A2'], ['A1',50], ['A2']])

Expected Output: [None, None, None, 11, None, 100, None, 100]

Explanation: A2 depends on A1 (=11). Overwriting A2 with the literal 100 drops the dependency edge, so a later A1->50 no longer affects A2 (still 100).

Input: (['Spreadsheet','set_cell','set_cell','set_cell','get_cell','set_cell','get_cell','get_cell'], [[], ['A1',1], ['B1','=A1+1'], ['C1','=B1+1'], ['C1'], ['A1','=C1'], ['A1'], ['C1']])

Expected Output: [None, None, None, None, 3, 'ValueError', 1, 3]

Explanation: Transitive chain A1<-B1<-C1 gives C1=3. Setting A1='=C1' closes the cycle A1->C1->B1->A1, so it raises ValueError and leaves the sheet unchanged (A1=1, C1=3).

Input: (['Spreadsheet','get_cell'], [[], ['Z9']])

Expected Output: [None, 0]

Explanation: Boundary: reading a cell that was never set returns 0.

Input: (['Spreadsheet','set_cell','set_cell','get_cell'], [[], ['AA10',3], ['B2','=AA10+AA10+4'], ['B2']])

Expected Output: [None, None, None, 10]

Explanation: Multi-letter cell id (AA10) and a repeated reference: B2 = AA10 + AA10 + 4 = 3+3+4 = 10.

Hints

  1. Store each cell as either a literal integer or a parsed formula (a list of terms). Do not evaluate formulas on write — the workload is write-heavy, so defer evaluation to get_cell.
  2. Maintain a dependency graph: for a formula cell, record the set of cells it references. get_cell then recursively sums literal terms and the current values of referenced cells (unset cells resolve to 0).
  3. Before committing a formula write to cell C with reference set R, check whether C is reachable from any cell in R through the existing dependency edges (DFS/BFS). If so, the edges C->R would close a cycle: raise ValueError and leave every stored cell untouched.
  4. A literal write can never create a cycle (it removes C's outgoing edges), so only formula writes need the cycle check.
Last updated: Jul 1, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • AI Coding Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • In-Memory File System: Create, Track Duplicates, and List - Harvey (medium)
  • Design an In-Memory Spreadsheet Engine - Harvey (hard)
  • Implement a Spreadsheet With Formulas - Harvey (medium)
  • Implement Spreadsheet Cell Updates - Harvey (hard)
  • Evaluate Symbol Expressions - Harvey (medium)