questions D-E
This commit is contained in:
190
backend/data/questions/excel-sheet-column-title.yaml
Normal file
190
backend/data/questions/excel-sheet-column-title.yaml
Normal file
@@ -0,0 +1,190 @@
|
||||
title: Excel Sheet Column Title
|
||||
slug: excel-sheet-column-title
|
||||
difficulty: easy
|
||||
leetcode_id: 168
|
||||
leetcode_url: https://leetcode.com/problems/excel-sheet-column-title/
|
||||
categories:
|
||||
- strings
|
||||
- math
|
||||
patterns:
|
||||
- greedy
|
||||
|
||||
function_signature: "def convert_to_title(column_number: int) -> str:"
|
||||
|
||||
test_cases:
|
||||
visible:
|
||||
- input: { column_number: 1 }
|
||||
expected: "A"
|
||||
- input: { column_number: 28 }
|
||||
expected: "AB"
|
||||
- input: { column_number: 701 }
|
||||
expected: "ZY"
|
||||
hidden:
|
||||
- input: { column_number: 26 }
|
||||
expected: "Z"
|
||||
- input: { column_number: 27 }
|
||||
expected: "AA"
|
||||
- input: { column_number: 52 }
|
||||
expected: "AZ"
|
||||
|
||||
description: |
|
||||
Given an integer `columnNumber`, return *its corresponding column title as it appears in an Excel sheet*.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
A -> 1
|
||||
B -> 2
|
||||
C -> 3
|
||||
...
|
||||
Z -> 26
|
||||
AA -> 27
|
||||
AB -> 28
|
||||
...
|
||||
```
|
||||
|
||||
constraints: |
|
||||
- `1 <= columnNumber <= 2^31 - 1`
|
||||
|
||||
examples:
|
||||
- input: "columnNumber = 1"
|
||||
output: '"A"'
|
||||
explanation: "The 1st column in Excel is labeled 'A'."
|
||||
- input: "columnNumber = 28"
|
||||
output: '"AB"'
|
||||
explanation: "After Z (26), we wrap to AA (27), then AB (28)."
|
||||
- input: "columnNumber = 701"
|
||||
output: '"ZY"'
|
||||
explanation: "701 = 26 * 26 + 25 = 676 + 25. The first character is Z (26th letter), and the second is Y (25th letter)."
|
||||
|
||||
explanation:
|
||||
intuition: |
|
||||
This problem is essentially converting a number to **base-26**, but with an important twist: Excel columns are **1-indexed**, not 0-indexed.
|
||||
|
||||
In standard base-26 (like hexadecimal is base-16), the digits would be 0-25. But Excel uses A-Z representing 1-26. There's no "zero" character!
|
||||
|
||||
Think of it like this: imagine you're reading an odometer, but instead of digits 0-9, you have letters A-Z. And unlike a normal odometer where 0 exists, this one starts at A (which represents 1).
|
||||
|
||||
The key insight is that before extracting each "digit", we need to **subtract 1** to shift from 1-indexed to 0-indexed. This converts our 1-26 range to 0-25, which maps perfectly to A-Z using modulo arithmetic.
|
||||
|
||||
For example, with `columnNumber = 28`:
|
||||
- Subtract 1 → 27
|
||||
- 27 % 26 = 1 → maps to 'B'
|
||||
- 27 // 26 = 1
|
||||
- Subtract 1 → 0
|
||||
- 0 % 26 = 0 → maps to 'A'
|
||||
- Result: "AB" (reversed from our extraction order)
|
||||
|
||||
approach: |
|
||||
We solve this using **repeated division with 1-index adjustment**:
|
||||
|
||||
**Step 1: Initialise result string**
|
||||
|
||||
- `result`: Empty string to build our column title
|
||||
|
||||
|
||||
|
||||
**Step 2: Extract characters from right to left**
|
||||
|
||||
- While `columnNumber > 0`:
|
||||
- **Subtract 1** from `columnNumber` to convert from 1-indexed to 0-indexed
|
||||
- Get the remainder when divided by 26 — this gives us the current character (0 = A, 1 = B, ..., 25 = Z)
|
||||
- Convert the remainder to a character using `chr(remainder + ord('A'))`
|
||||
- **Prepend** this character to the result (or append and reverse at the end)
|
||||
- Divide `columnNumber` by 26 to move to the next position
|
||||
|
||||
|
||||
|
||||
**Step 3: Return the result**
|
||||
|
||||
- Return the constructed column title string
|
||||
|
||||
|
||||
|
||||
The subtraction step is crucial — it handles the fact that there's no "zero" in Excel's numbering. Without it, 'Z' (26) would incorrectly produce 'AZ' instead of just 'Z'.
|
||||
|
||||
common_pitfalls:
|
||||
- title: Forgetting the 1-Index Adjustment
|
||||
description: |
|
||||
The most common mistake is treating this as standard base-26 conversion without accounting for 1-indexing.
|
||||
|
||||
For example, without subtracting 1:
|
||||
- `columnNumber = 26` → 26 % 26 = 0, 26 // 26 = 1 → gives "A" + something
|
||||
- But the answer should be just "Z"!
|
||||
|
||||
The subtraction converts our 1-26 range to 0-25, making the modulo operation work correctly.
|
||||
wrong_approach: "Direct modulo without adjustment"
|
||||
correct_approach: "Subtract 1 before each modulo operation"
|
||||
|
||||
- title: Building String in Wrong Order
|
||||
description: |
|
||||
When extracting digits via repeated division, we get them in reverse order (rightmost first). A common error is appending characters and forgetting to reverse, or getting confused about which end to add to.
|
||||
|
||||
For `28`:
|
||||
- First extraction gives 'B' (the rightmost character)
|
||||
- Second extraction gives 'A' (the leftmost character)
|
||||
- If we append: "BA" (wrong!)
|
||||
- If we prepend: "AB" (correct!)
|
||||
wrong_approach: "Appending characters without reversing"
|
||||
correct_approach: "Prepend each character, or append then reverse at the end"
|
||||
|
||||
- title: Off-By-One with Character Mapping
|
||||
description: |
|
||||
After the modulo operation, the remainder is 0-25. Some implementations incorrectly use `chr(remainder + ord('A') + 1)` or similar, resulting in off-by-one errors.
|
||||
|
||||
Remember: remainder 0 should map to 'A', remainder 1 to 'B', etc. Since `ord('A')` is 65, we use `chr(remainder + 65)` or `chr(remainder + ord('A'))`.
|
||||
|
||||
key_takeaways:
|
||||
- "**1-indexed systems require adjustment**: When a numbering system starts at 1 instead of 0, subtract 1 before modulo operations"
|
||||
- "**Base conversion pattern**: This technique of repeated division and modulo extends to any base conversion (binary, hex, etc.)"
|
||||
- "**Build strings carefully**: When extracting digits right-to-left, remember to reverse or prepend"
|
||||
- "**Related problems**: Excel Sheet Column Number (LC 171) is the inverse operation — converting title back to number"
|
||||
|
||||
time_complexity: "O(log<sub>26</sub> n). Each iteration divides the number by 26, so we perform approximately log base 26 of n iterations."
|
||||
space_complexity: "O(log<sub>26</sub> n). The output string length is proportional to the number of iterations."
|
||||
|
||||
solutions:
|
||||
- approach_name: Iterative Division
|
||||
is_optimal: true
|
||||
code: |
|
||||
def convert_to_title(column_number: int) -> str:
|
||||
result = []
|
||||
|
||||
while column_number > 0:
|
||||
# Subtract 1 to convert from 1-indexed to 0-indexed
|
||||
column_number -= 1
|
||||
|
||||
# Get the current character (0 = A, 1 = B, ..., 25 = Z)
|
||||
remainder = column_number % 26
|
||||
result.append(chr(remainder + ord('A')))
|
||||
|
||||
# Move to the next position
|
||||
column_number //= 26
|
||||
|
||||
# We built the string right-to-left, so reverse it
|
||||
return ''.join(reversed(result))
|
||||
explanation: |
|
||||
**Time Complexity:** O(log<sub>26</sub> n) — We divide by 26 each iteration.
|
||||
|
||||
**Space Complexity:** O(log<sub>26</sub> n) — The result list stores one character per iteration.
|
||||
|
||||
The key insight is subtracting 1 before each modulo operation. This converts from Excel's 1-indexed system (A=1, Z=26) to a 0-indexed system (A=0, Z=25) that works naturally with modulo arithmetic.
|
||||
|
||||
- approach_name: Recursive Solution
|
||||
is_optimal: false
|
||||
code: |
|
||||
def convert_to_title(column_number: int) -> str:
|
||||
if column_number == 0:
|
||||
return ""
|
||||
|
||||
# Subtract 1 for 1-indexed adjustment
|
||||
column_number -= 1
|
||||
|
||||
# Recursively get the prefix, then append current character
|
||||
return convert_to_title(column_number // 26) + chr(column_number % 26 + ord('A'))
|
||||
explanation: |
|
||||
**Time Complexity:** O(log<sub>26</sub> n) — Same number of operations as iterative.
|
||||
|
||||
**Space Complexity:** O(log<sub>26</sub> n) — Call stack depth plus result string.
|
||||
|
||||
This recursive approach builds the string naturally in the correct order by recursing first (handling higher-order digits) then appending the current character. While elegant, it uses additional stack space compared to the iterative solution.
|
||||
Reference in New Issue
Block a user