A clear explanation of converting an Excel column title into its numeric index using base 26 accumulation.
Problem Restatement
We are given an Excel column title:
columnTitleWe need to return its corresponding column number.
Excel columns are labeled like this:
| Title | Number |
|---|---|
"A" | 1 |
"B" | 2 |
"Z" | 26 |
"AA" | 27 |
"AB" | 28 |
"ZY" | 701 |
This problem is the reverse of LeetCode 168.
The input contains only uppercase English letters. The constraints guarantee the answer fits in a 32-bit integer. (leetcode.com)
Input and Output
| Item | Meaning |
|---|---|
| Input | Excel column title string |
| Output | Corresponding integer |
| Alphabet | Uppercase A through Z |
| Digit mapping | A = 1, …, Z = 26 |
| Important detail | No zero digit exists |
Example function shape:
def titleToNumber(columnTitle: str) -> int:
...Examples
Example 1:
columnTitle = "A"Output:
1Example 2:
columnTitle = "AB"Compute:
A = 1
B = 2So:
1 * 26 + 2 = 28Return:
28Example 3:
columnTitle = "ZY"Compute:
Z = 26
Y = 25So:
26 * 26 + 25 = 701Return:
701First Thought: This Is Like Base 26
This looks similar to converting a number written in base 26.
For example:
"AB"behaves like:
1 * 26 + 2But there is one important difference.
Normal base 26 digits are:
0 through 25Excel digits are:
1 through 26Still, the accumulation process is almost identical to normal positional notation.
Key Insight
Process the string from left to right.
Suppose we already computed the value of the prefix.
When we read a new character, shift the old value left by one base-26 position:
result *= 26Then add the new digit value.
Character conversion:
"A" -> 1
"B" -> 2
...
"Z" -> 26We can compute this using ASCII codes:
ord(ch) - ord("A") + 1Why the Formula Works
Suppose we process:
"AB"Start:
result = 0Read "A":
result = 0 * 26 + 1 = 1Read "B":
result = 1 * 26 + 2 = 28This matches the Excel column number.
The multiplication by 26 shifts previous digits one position to the left, exactly like decimal numbers use multiplication by 10.
Algorithm
Initialize:
result = 0For each character ch in columnTitle:
- Convert the character into its numeric value.
- Multiply
resultby26. - Add the digit value.
Return result.
Walkthrough
Use:
columnTitle = "ZY"Start:
result = 0Read "Z":
value = 26
result = 0 * 26 + 26 = 26Read "Y":
value = 25
result = 26 * 26 + 25 = 701Return:
701Correctness
The algorithm processes the column title from left to right.
Suppose after processing the first k characters, result equals the correct numeric value of that prefix.
When the next character is read, multiplying by 26 shifts the previous value one Excel digit position to the left. Adding the new character value appends the new digit in the least significant position.
Because Excel titles use positional notation with base 26 and digits 1 through 26, this update rule exactly matches the mathematical meaning of the title.
The algorithm starts from 0 and processes every character once, so after the final character, result equals the correct Excel column number.
Complexity
Let n be the length of columnTitle.
| Metric | Value | Why |
|---|---|---|
| Time | O(n) | We scan each character once |
| Space | O(1) | Only one accumulator is used |
Implementation
class Solution:
def titleToNumber(self, columnTitle: str) -> int:
result = 0
for ch in columnTitle:
value = ord(ch) - ord("A") + 1
result = result * 26 + value
return resultCode Explanation
Start with:
result = 0Process each character:
for ch in columnTitle:Convert the character into a number:
value = ord(ch) - ord("A") + 1Examples:
| Character | Value |
|---|---|
"A" | 1 |
"B" | 2 |
"Z" | 26 |
Shift the previous digits left:
result = result * 26Then append the new digit:
result = result + valueCombined:
result = result * 26 + valueFinally:
return resultreturns the Excel column number.
Recursive Implementation
We can also solve this recursively.
class Solution:
def titleToNumber(self, columnTitle: str) -> int:
if not columnTitle:
return 0
prefix = self.titleToNumber(columnTitle[:-1])
current = ord(columnTitle[-1]) - ord("A") + 1
return prefix * 26 + currentThe iterative solution is simpler and avoids recursion overhead.
Testing
def run_tests():
sol = Solution()
assert sol.titleToNumber("A") == 1
assert sol.titleToNumber("B") == 2
assert sol.titleToNumber("Z") == 26
assert sol.titleToNumber("AA") == 27
assert sol.titleToNumber("AB") == 28
assert sol.titleToNumber("AZ") == 52
assert sol.titleToNumber("BA") == 53
assert sol.titleToNumber("ZY") == 701
assert sol.titleToNumber("ZZ") == 702
assert sol.titleToNumber("AAA") == 703
print("all tests passed")
run_tests()| Test | Why |
|---|---|
"A" | First column |
"Z" | Largest one-letter title |
"AA" | First two-letter title |
"AB" | Standard example |
"AZ" | Ends with Z |
"BA" | Carries into next leading digit |
"ZY" | Standard larger example |
"ZZ" | Largest two-letter title |
"AAA" | First three-letter title |