Excel Sheet Column Title looks like a base-26 conversion and is not quite. Excel's columns have no zero — the digits run A to Z with no symbol for "nothing" — and that single missing digit is the entire problem. The fix is one line, and knowing why it is needed is what separates a working solution from a lucky one.
The problem
Given a positive integer, return its Excel column title.
1 -> "A"
26 -> "Z"
27 -> "AA"
28 -> "AB"
52 -> "AZ"
53 -> "BA"
701 -> "ZY"
702 -> "ZZ"
703 -> "AAA"26 → "Z" and 27 → "AA" are the two to check any solution against. They
are exactly where ordinary base-26 goes wrong.
Why plain base-26 fails
Normal base-26 has digits 0–25. Excel has 26 digits, A–Z, and they represent 1–26. There is no zero:
base 26: 0, 1, 2, ..., 25, then 10 (meaning 26)
Excel: A, B, C, ..., Z, then AA (meaning 27)
26 % 26 = 0 -> there is no digit for 0, and Z is what we wantThis is called a bijective numeral system: every positive integer has exactly one representation and no representation has a leading-zero ambiguity, because zero does not exist. Naming it is worth a sentence — it tells the interviewer you have identified the actual structure rather than patched until the tests passed.
The one-line fix
while (n > 0) {
n--; <- shift THIS digit into 0..25
digit = 'A' + n % 26;
n /= 26;
}Decrementing before taking the remainder converts the 1–26 digit into a 0–25 one, so the arithmetic becomes ordinary base-26 for that step. The decrement must happen inside the loop, once per digit — doing it once before the loop fixes 26 and breaks 27.
n = 28: n-- -> 27, 27 % 26 = 1 -> 'B', 27 / 26 = 1
n-- -> 0, 0 % 26 = 0 -> 'A', 0 / 26 = 0
reversed: "AB"
n = 26: n-- -> 25, 25 % 26 = 25 -> 'Z', 25 / 26 = 0
reversed: "Z"Java
class Solution {
public String convertToTitle(int columnNumber) {
StringBuilder title = new StringBuilder();
while (columnNumber > 0) {
// Excel's digits are 1..26 with no zero, so shift this one to 0..25.
columnNumber--;
title.append((char) ('A' + columnNumber % 26));
columnNumber /= 26;
}
return title.reverse().toString();
}
}Digits come out least-significant first, so the result is reversed once at the end —
O(n) in the length of the title. Inserting at index 0 each iteration would be
O(n²), the same trap as
Add Binary and
postorder traversal.
No overflow concern: the loop only divides. The inverse problem (Excel Sheet Column Number, 171) multiplies and does need the check.
Python
class Solution:
def convertToTitle(self, columnNumber: int) -> str:
title = []
while columnNumber > 0:
columnNumber -= 1 # 1..26 becomes 0..25
title.append(chr(ord("A") + columnNumber % 26))
columnNumber //= 26
return "".join(reversed(title))// and not /. Python's / produces a float, and
columnNumber would silently become 26.0, then 1.0, and
chr would raise on a float argument — a crash rather than a wrong answer, but a crash
that only appears past 26.
Build a list and join, rather than concatenating strings in a loop. Same reasoning as the Java reversal.
Complexity
| Time | Space | |
|---|---|---|
| Digit extraction | O(log₂₆ n) | O(log₂₆ n) output |
One iteration per output character, and the title has about log₂₆ n of them —
Integer.MAX_VALUE is "FXSHRXW", seven characters. Effectively constant, but
say the logarithm rather than "constant"; the interviewer is checking that you know what the loop
is bounded by.
The inverse, and the sanity check
Excel Sheet Column Number (171) goes the other way and is the easier direction, precisely because no shift is needed:
result = 0
for each character c:
result = result * 26 + (c - 'A' + 1) the +1 IS the bijective partThe two are inverses, which makes an excellent self-check: convert every number in a range to a title and back, and confirm you get the original. That round-trip catches every off-by-one the shift can produce, and it is the sort of test worth proposing out loud even when you cannot run it.
Where else bijective numbering shows up
Anywhere labels start at 1 rather than 0 and then carry: spreadsheet columns, some invoice numbering schemes, and bijective base-k in combinatorics. The give-away is a system where k symbols represent 1..k rather than 0..k−1, and the fix is always the same decrement.
What the interviewer is checking
- That you notice there is no zero digit, and can name why that matters.
- The decrement inside the loop, once per digit — not once before it.
- 26 →
"Z"and 27 →"AA", the two boundary cases. - Reversing once rather than prepending in a loop.
- Integer division in Python.
- That you can state the inverse and propose the round-trip check.