Your task is to design the basic function of an Excel-like program. You will be given a string array formula
of size m x n
representing the contents of the Excel sheet. The sheet is an m x n
grid where each cell contains either an integer or a formula.
Specifically, you are to implement the Excel
class:
Excel(int height, char width)
Initializes the object with a sheet of the given dimensions.height
is a positive integer representing the height of the sheet.width
is a character representing the width of the sheet. The sheet is represented as an height x width
grid where the first row and column use 1-based indexing and are represented as integers and characters, respectively.void set(int row, char column, int val)
Changes the value at row
and column
to val
.int get(int row, char column)
Returns the value at row
and column
. If the cell contains a formula, evaluate the formula and return the result.int sum(int row, char column, string[] numbers)
Sets the formula at row
and column
to be the sum of cells represented by numbers
and returns the result.numbers
represents the location of a cell that contributes to the sum."ColRow"
, where Col
represents the column number as an uppercase letter and Row
represents the row number as a string."ColRow1:ColRow2"
, where Col
represents the column number as an uppercase letter, Row1
represents the row number as a string, and Row2
represents the end row number as a string. You can assume that Row1 <= Row2
.Example:
Excel excel = new Excel(3, 'C'); // sheet is arranged as such: // A1 = 1, B1 = 2, C1 = 3 // A2 = 4, B2 = 5, C2 = 6 // A3 = 7, B3 = 8, C3 = 9 excel.set(1, 'A', 2); // sheet is arranged as such: // A1 = 2, B1 = 2, C1 = 3 // A2 = 4, B2 = 5, C2 = 6 // A3 = 7, B3 = 8, C3 = 9 excel.sum(3, 'C', new String[] {"A1", "A1:B2"}); // return 10 // C3 = A1 + A1 + B1 + A2 + B2 excel.get(3, 'C'); // return 10 excel.set(2, 'B', 2); // sheet is arranged as such: // A1 = 2, B1 = 2, C1 = 3 // A2 = 4, B2 = 2, C2 = 6 // A3 = 7, B3 = 8, C3 = 9 excel.sum(3, 'C', new String[] {"A1", "A1:B2"}); // return 8 // C3 = A1 + A1 + B1 + A2 + B2
Constraints:
1 <= height <= 26
'A' <= width <= 'Z'
1 <= row <= height
'A' <= column <= width
-100 <= val <= 100
1 <= numbers.length <= 5
100 <= get(row, column) <= 200
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
Imagine each cell in the Excel sheet holds a number. The sum formula tells a cell to calculate its value by adding up the values of other cells. The brute force method tries every possible combination of the cells being referenced.
Here's how the algorithm would work step-by-step:
def design_excel_sum_formula_brute_force(cell_with_formula, referenced_cells):
# Simulate different states of referenced cells by creating combinations
number_of_referenced_cells = len(referenced_cells)
possible_combinations = []
if number_of_referenced_cells > 0:
possible_combinations = [ {} ]
for referenced_cell in referenced_cells:
possible_combinations[0][referenced_cell] = 1
else:
return 0
final_result = 0
for combination in possible_combinations:
# Evaluate sum formulas in referenced cells for current combination
evaluated_referenced_cells = {}
for referenced_cell in combination:
if isinstance(referenced_cells[referenced_cell], str) and referenced_cells[referenced_cell].startswith('='):
# Recalculate the values of the referenced cells that have sum formulas
evaluated_referenced_cells[referenced_cell] = evaluate_sum_formula(referenced_cells[referenced_cell], referenced_cells)
else:
evaluated_referenced_cells[referenced_cell] = referenced_cells[referenced_cell]
# Calculate the final value of the cell with the sum formula
final_result = evaluate_sum_formula(cell_with_formula, referenced_cells, evaluated_referenced_cells)
return final_result
def evaluate_sum_formula(formula, all_cells, evaluated_referenced_cells = None):
formula = formula.replace('=', '')
terms = formula.split('+')
total = 0
for term in terms:
term = term.strip()
try:
# Check if term is a number
total += float(term)
except ValueError:
# Or check if the term is a referenced cell to add to the total
if term in all_cells:
if evaluated_referenced_cells and term in evaluated_referenced_cells:
total += float(evaluated_referenced_cells[term])
else:
total += float(all_cells[term])
else:
total += 0
return total
To efficiently calculate the sum based on a formula, we need to track dependencies between cells. The optimal approach involves building a dependency graph and then using it to compute cell values in the correct order, avoiding redundant calculations.
Here's how the algorithm would work step-by-step:
class Excel:
def __init__(self, height, width):
self.height = height
self.width = width
self.cells = [[''] * width for _ in range(height)]
self.values = [[0] * width for _ in range(height)]
self.dependency_graph = [[set() for _ in range(width)] for _ in range(height)]
def set(self, row, column, value):
self.cells[row][column] = str(value)
self.dependency_graph = [[set() for _ in range(self.width)] for _ in range(self.height)]
self.calculate_cell(row, column)
def get(self, row, column):
return self.values[row][column]
def sum(self, row, column, formula):
self.cells[row][column] = formula
self.dependency_graph = [[set() for _ in range(self.width)] for _ in range(self.height)]
self.calculate_cell(row, column)
def calculate_cell(self, row, column):
formula = self.cells[row][column]
if formula == '':
self.values[row][column] = 0
return
if formula.isdigit():
self.values[row][column] = int(formula)
return
self.values[row][column] = self.evaluate_formula(row, column, formula)
#After updating value, recalculate dependants
for dependant_row in range(self.height):
for dependant_column in range(self.width):
if (row, column) in self.dependency_graph[dependant_row][dependant_column]:
self.calculate_cell(dependant_row, dependant_column)
def evaluate_formula(self, row, column, formula):
total = 0
parts = formula.split('+')
for part in parts:
if ':' in part:
start, end = part.split(':')
start_row = ord(start[0]) - ord('A')
start_col = int(start[1:]) - 1
end_row = ord(end[0]) - ord('A')
end_col = int(end[1:]) - 1
# Add cell to dependency graph before calculating
for i in range(start_row, end_row + 1):
for j in range(start_col, end_col + 1):
self.dependency_graph[row][column].add((i, j))
total += self.values[i][j]
else:
cell_row = ord(part[0]) - ord('A')
cell_col = int(part[1:]) - 1
# Add cell to dependency graph before calculating
self.dependency_graph[row][column].add((cell_row, cell_col))
total += self.values[cell_row][cell_col]
return total
Case | How to Handle |
---|---|
rows or cols are zero | Return 0 for sum, or handle gracefully in set by potentially not creating the grid |
row1 > row2 or col1 > col2 | Swap row1 and row2 if row1 > row2, and col1 and col2 if col1 > col2 to ensure valid rectangle definition |
row or col indices are out of bounds (negative or exceed dimensions) | Return 0 for sum when accessing out of bounds or raise an exception, and ignore set if out of bounds |
Large dimensions (rows and cols) leading to high memory usage | Consider using sparse matrix or lazy evaluation techniques if memory becomes a bottleneck |
Integer overflow when calculating the sum | Use a data type with a larger range (e.g., long) for the sum to avoid overflow |
Negative values in the grid | The sum calculation should correctly handle negative values by adding them with appropriate signs |
row1 equals row2 and col1 equals col2 (single cell region) | Return the value of that single cell for the sum |
Extreme values in cells that, when summed, cause integer overflow even with a larger datatype | Implement overflow detection and handle accordingly (e.g., throw exception or cap the sum) |