2194. Cells in a Range on an Excel Sheet
Problem Description
You are given a string that represents a rectangular range of cells in an Excel sheet. The string follows the format "<col1><row1>:<col2><row2>"
, where:
- The first part
<col1><row1>
represents the top-left cell - The second part
<col2><row2>
represents the bottom-right cell - These two parts are separated by a colon
:
In Excel notation:
- Columns are represented by letters (
'A'
for column 1,'B'
for column 2,'C'
for column 3, and so on) - Rows are represented by numbers (1, 2, 3, ...)
For example, "A1:C3"
represents a 3×3 grid from cell A1 to cell C3.
Your task is to return a list of all cells within this rectangular range (inclusive of boundaries). The cells should be:
- Represented as strings in Excel format (like
"A1"
,"B2"
, etc.) - Sorted first by column (A before B before C) and then by row (1 before 2 before 3)
The solution iterates through the range by:
- Extracting the start column
s[0]
and end columns[-2]
(the third character from the end) - Extracting the start row
s[1]
and end rows[-1]
(the last character) - Using nested loops to generate all cells, with the outer loop for columns and inner loop for rows
- Converting column indices back to letters using
chr()
andord()
functions
For instance, if the input is "K1:L2"
, the output would be ["K1", "K2", "L1", "L2"]
.
Intuition
The key insight is recognizing that we need to generate all cells in a rectangular grid. Think of it like filling in all the squares on a checkerboard within a given rectangle.
Since the input format is fixed ("<col1><row1>:<col2><row2>"
), we can extract the boundaries directly:
- The first character is the starting column
- The second character is the starting row
- The second-to-last character is the ending column
- The last character is the ending row
To generate all cells systematically, we need to iterate through every combination of columns and rows within our boundaries. This naturally suggests using nested loops.
The ordering requirement (sorted by column first, then by row) tells us which loop should be outer and which should be inner. Since we want all rows of column A before moving to column B, we make columns the outer loop and rows the inner loop.
For working with column letters, we leverage ASCII values. In ASCII, letters are consecutive numbers ('A'
= 65, 'B'
= 66, etc.), so we can:
- Convert a letter to its ASCII value with
ord()
- Iterate through consecutive numbers
- Convert back to letters with
chr()
This approach is straightforward because Excel's column naming (A, B, C...) maps directly to consecutive ASCII values, making the conversion trivial. The row numbers are already integers in the string, so we just need to extract and iterate through them.
The beauty of this solution is its simplicity - we're essentially just enumerating all points in a rectangle, taking advantage of Python's list comprehension to make the code concise and readable.
Solution Approach
The solution uses a straightforward simulation approach with list comprehension to generate all cells in the specified range.
Step-by-step implementation:
-
Parse the input string boundaries:
- Starting column:
s[0]
(first character) - Starting row:
s[1]
(second character) - Ending column:
s[-2]
(second-to-last character, skipping the last row digit) - Ending row:
s[-1]
(last character)
- Starting column:
-
Generate the column range:
- Convert the starting column letter to ASCII using
ord(s[0])
- Convert the ending column letter to ASCII using
ord(s[-2])
- Create a range from start to end (inclusive) by adding 1:
range(ord(s[0]), ord(s[-2]) + 1)
- Convert the starting column letter to ASCII using
-
Generate the row range:
- Convert the starting row from string to integer:
int(s[1])
- Convert the ending row from string to integer:
int(s[-1])
- Create a range from start to end (inclusive):
range(int(s[1]), int(s[-1]) + 1)
- Convert the starting row from string to integer:
-
Build each cell string:
- For each column index
i
, convert back to letter usingchr(i)
- For each row index
j
, convert to string usingstr(j)
- Concatenate them:
chr(i) + str(j)
- For each column index
-
Use nested iteration with list comprehension:
[chr(i) + str(j) for i in range(ord(s[0]), ord(s[-2]) + 1) for j in range(int(s[1]), int(s[-1]) + 1)]
The outer loop iterates through columns, and the inner loop iterates through rows, ensuring the correct sorting order (column-major).
Example walkthrough with "K1:L2"
:
- Column range:
ord('K')
toord('L')
→ 75 to 76 - Row range: 1 to 2
- Generation order:
i=75, j=1
→chr(75) + '1'
→"K1"
i=75, j=2
→chr(75) + '2'
→"K2"
i=76, j=1
→chr(76) + '1'
→"L1"
i=76, j=2
→chr(76) + '2'
→"L2"
- Result:
["K1", "K2", "L1", "L2"]
The time complexity is O(m × n)
where m
is the number of columns and n
is the number of rows in the range, as we must generate each cell. The space complexity is also O(m × n)
for storing the result list.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with the input "B2:D4"
.
Step 1: Parse the boundaries
- Starting column:
s[0]
='B'
- Starting row:
s[1]
='2'
- Ending column:
s[-2]
='D'
(second-to-last character) - Ending row:
s[-1]
='4'
(last character)
Step 2: Convert columns to ASCII values
ord('B')
= 66ord('D')
= 68- Column range: 66 to 68 (inclusive)
Step 3: Convert rows to integers
int('2')
= 2int('4')
= 4- Row range: 2 to 4 (inclusive)
Step 4: Generate all cells using nested loops
The list comprehension executes in this order:
i = 66 (column B): j = 2: chr(66) + '2' = 'B' + '2' = "B2" j = 3: chr(66) + '3' = 'B' + '3' = "B3" j = 4: chr(66) + '4' = 'B' + '4' = "B4" i = 67 (column C): j = 2: chr(67) + '2' = 'C' + '2' = "C2" j = 3: chr(67) + '3' = 'C' + '3' = "C3" j = 4: chr(67) + '4' = 'C' + '4' = "C4" i = 68 (column D): j = 2: chr(68) + '2' = 'D' + '2' = "D2" j = 3: chr(68) + '3' = 'D' + '3' = "D3" j = 4: chr(68) + '4' = 'D' + '4' = "D4"
Final Result: ["B2", "B3", "B4", "C2", "C3", "C4", "D2", "D3", "D4"]
Notice how the cells are naturally sorted by column first (all B's, then all C's, then all D's) and within each column by row number (2, 3, 4). This ordering is achieved by making columns the outer loop and rows the inner loop in our list comprehension.
Solution Implementation
1class Solution:
2 def cellsInRange(self, s: str) -> List[str]:
3 """
4 Generate all cells in a rectangular range on a spreadsheet.
5
6 Args:
7 s: A string in format "C1:R2" representing the range from top-left to bottom-right cell
8
9 Returns:
10 A list of strings representing all cells in the range in row-major order
11 """
12 # Extract start and end column characters
13 start_col = s[0] # First character is the starting column
14 end_col = s[3] # Fourth character (after ':') is the ending column
15
16 # Extract start and end row numbers
17 start_row = int(s[1]) # Second character is the starting row number
18 end_row = int(s[4]) # Fifth character is the ending row number
19
20 # Generate all cells in the range using list comprehension
21 result = []
22 for col_ascii in range(ord(start_col), ord(end_col) + 1):
23 for row_num in range(start_row, end_row + 1):
24 # Convert ASCII value back to character and concatenate with row number
25 cell = chr(col_ascii) + str(row_num)
26 result.append(cell)
27
28 return result
29
1class Solution {
2 /**
3 * Returns all cells in a rectangular range on an Excel sheet.
4 *
5 * @param s A string representing the range in format "C1R1:C2R2"
6 * where C1, C2 are column letters and R1, R2 are row numbers
7 * @return List of all cells in the range in lexicographical order
8 */
9 public List<String> cellsInRange(String s) {
10 List<String> result = new ArrayList<>();
11
12 // Extract range boundaries from input string
13 char startColumn = s.charAt(0); // First column letter
14 char startRow = s.charAt(1); // First row number
15 char endColumn = s.charAt(3); // Last column letter (after ':')
16 char endRow = s.charAt(4); // Last row number (after ':')
17
18 // Iterate through all columns in the range
19 for (char column = startColumn; column <= endColumn; column++) {
20 // For each column, iterate through all rows in the range
21 for (char row = startRow; row <= endRow; row++) {
22 // Construct cell reference by concatenating column and row
23 String cell = "" + column + row;
24 result.add(cell);
25 }
26 }
27
28 return result;
29 }
30}
31
1class Solution {
2public:
3 vector<string> cellsInRange(string s) {
4 // Result vector to store all cells in the range
5 vector<string> result;
6
7 // Extract range boundaries from input string
8 // s[0] = start column (e.g., 'A')
9 // s[1] = start row (e.g., '1')
10 // s[3] = end column (e.g., 'C')
11 // s[4] = end row (e.g., '3')
12 char startColumn = s[0];
13 char startRow = s[1];
14 char endColumn = s[3];
15 char endRow = s[4];
16
17 // Iterate through all columns from start to end (inclusive)
18 for (char currentColumn = startColumn; currentColumn <= endColumn; ++currentColumn) {
19 // For each column, iterate through all rows from start to end (inclusive)
20 for (char currentRow = startRow; currentRow <= endRow; ++currentRow) {
21 // Create cell reference string and add to result
22 // Using initializer list to construct string from two characters
23 result.push_back({currentColumn, currentRow});
24 }
25 }
26
27 return result;
28 }
29};
30
1/**
2 * Returns all cells in a rectangular range defined by a string in Excel-like format
3 * @param s - Range string in format "C1:R3" where first part is top-left cell and second part is bottom-right cell
4 * @returns Array of all cell names within the specified range
5 */
6function cellsInRange(s: string): string[] {
7 // Array to store all cell names in the range
8 const result: string[] = [];
9
10 // Extract column and row boundaries from the range string
11 // s[0] = start column letter, s[3] = end column letter
12 const startColumn: number = s.charCodeAt(0);
13 const endColumn: number = s.charCodeAt(3);
14
15 // s[1] = start row number, s[4] = end row number
16 const startRow: number = s.charCodeAt(1);
17 const endRow: number = s.charCodeAt(4);
18
19 // Iterate through all columns from start to end (inclusive)
20 for (let currentColumn: number = startColumn; currentColumn <= endColumn; currentColumn++) {
21 // For each column, iterate through all rows from start to end (inclusive)
22 for (let currentRow: number = startRow; currentRow <= endRow; currentRow++) {
23 // Convert ASCII codes back to characters and combine column letter with row number
24 const cellName: string = String.fromCharCode(currentColumn) + String.fromCharCode(currentRow);
25 result.push(cellName);
26 }
27 }
28
29 return result;
30}
31
Time and Space Complexity
The time complexity is O(m × n)
, where m
is the number of columns (letters) in the range and n
is the number of rows (digits) in the range.
m = ord(s[-2]) - ord(s[0]) + 1
represents the range of columns from the first character to the third character in the input stringn = int(s[-1]) - int(s[1]) + 1
represents the range of rows from the second character to the fourth character in the input string- The nested list comprehension iterates through all
m
columns and for each column, iterates through alln
rows, resulting inm × n
total iterations
The space complexity is O(m × n)
as the function creates and returns a list containing m × n
strings, where each string represents a cell in the specified range.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Index Assumptions for Multi-Digit Row Numbers
The most critical pitfall in this solution is assuming fixed positions for parsing the input string. The code uses hardcoded indices like s[1]
, s[4]
, and s[3]
to extract row and column information, which fails when row numbers have multiple digits.
Problem Example:
- Input:
"A1:B10"
- The code incorrectly parses:
s[3]
as':'
(not a column letter)s[4]
as'B'
(not a row number)- This causes errors or incorrect results
Solution:
class Solution:
def cellsInRange(self, s: str) -> List[str]:
# Split by colon to separate start and end cells
start_cell, end_cell = s.split(':')
# Parse start cell (column is first letter, rest is row number)
start_col = start_cell[0]
start_row = int(start_cell[1:])
# Parse end cell (column is first letter, rest is row number)
end_col = end_cell[0]
end_row = int(end_cell[1:])
result = []
for col_ascii in range(ord(start_col), ord(end_col) + 1):
for row_num in range(start_row, end_row + 1):
cell = chr(col_ascii) + str(row_num)
result.append(cell)
return result
2. Assuming Single-Letter Columns Only
The code assumes columns are always single letters (A-Z), but Excel notation supports multi-letter columns (AA, AB, etc.) for sheets with more than 26 columns.
Problem Example:
- Input:
"AA1:AB2"
- The current parsing logic would fail completely
Enhanced Solution for Multi-Letter Columns:
class Solution:
def cellsInRange(self, s: str) -> List[str]:
def parse_cell(cell_str):
"""Extract column letters and row number from a cell string"""
i = 0
while i < len(cell_str) and cell_str[i].isalpha():
i += 1
return cell_str[:i], int(cell_str[i:])
def column_to_number(col_str):
"""Convert column letters to a number (A=1, B=2, ..., AA=27, etc.)"""
result = 0
for char in col_str:
result = result * 26 + (ord(char) - ord('A') + 1)
return result
def number_to_column(num):
"""Convert a number back to column letters"""
result = ""
while num > 0:
num -= 1
result = chr(num % 26 + ord('A')) + result
num //= 26
return result
# Split and parse cells
start_cell, end_cell = s.split(':')
start_col, start_row = parse_cell(start_cell)
end_col, end_row = parse_cell(end_cell)
# Convert columns to numbers for iteration
start_col_num = column_to_number(start_col)
end_col_num = column_to_number(end_col)
# Generate all cells
result = []
for col_num in range(start_col_num, end_col_num + 1):
col_str = number_to_column(col_num)
for row_num in range(start_row, end_row + 1):
result.append(col_str + str(row_num))
return result
3. Not Validating Input Format
The code doesn't validate that the input follows the expected format, which could lead to runtime errors or unexpected behavior.
Solution with Input Validation:
class Solution:
def cellsInRange(self, s: str) -> List[str]:
# Validate input format
if ':' not in s:
raise ValueError("Input must contain ':' separator")
parts = s.split(':')
if len(parts) != 2:
raise ValueError("Input must have exactly one ':' separator")
# Continue with parsing...
These pitfalls highlight the importance of carefully analyzing input constraints and avoiding hardcoded assumptions about data format when parsing strings.
How would you design a stack which has a function min
that returns the minimum element in the stack, in addition to push
and pop
? All push
, pop
, min
should have running time O(1)
.
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!