Last Updated: March 31, 2026
At first glance, this looks like a simple base-26 conversion. You take a number, convert it to base 26, and map each digit to a letter. But there is a twist that trips up a lot of people.
Standard number systems are 0-indexed. In base 10, digits go from 0 to 9. In base 26, you would expect digits from 0 to 25. But Excel columns are 1-indexed: they go from A (1) to Z (26), with no digit representing 0. There is no "zero" column.
This means you cannot just do columnNumber % 26 and call it a day. When columnNumber is a multiple of 26 (like 26, 52, or 702), a naive mod gives you 0, but the correct letter is Z (which represents 26). The fix is to subtract 1 before each modulo operation, effectively shifting from 1-indexed to 0-indexed at each step: (columnNumber - 1) % 26 gives a value from 0 to 25, which maps cleanly to A through Z.
1 <= columnNumber <= 2^31 - 1 -> The number can be up to about 2.1 billion. Any approach that processes one digit at a time runs in O(log_26(n)) time, which is at most about 7 iterations.The most natural way to convert a number to a different base is to repeatedly take the remainder when dividing by the base, then divide the number by the base. For base 10, you would do n % 10 to get the last digit, then n = n / 10 to move to the next digit.
For Excel columns, the idea is the same, but with base 26 and a 1-indexing twist. Before taking the modulo, we subtract 1 from the number. This converts the 1-26 range into 0-25, which maps perfectly to A-Z. After getting the remainder, we divide the adjusted number by 26 and repeat until the number reaches 0.
Since we extract digits from the least significant position first (rightmost character), we build the result in reverse and flip it at the end.
columnNumber is greater than 0:columnNumber (shift from 1-indexed to 0-indexed).remainder = columnNumber % 26.remainder (0 maps to 'A', 1 maps to 'B', ..., 25 maps to 'Z').columnNumber = columnNumber / 26.columnNumber by 26, so the loop runs at most ceil(log_26(n)) times. For the maximum value of 2^31 - 1, that is about 7 iterations.The iterative approach is already very efficient. But it builds the string backwards and reverses at the end. What if we built it in the correct order from the start?
Instead of building the string from the rightmost character and reversing, we can use recursion to handle the "higher" digits first. The idea is: before appending the current character, recursively process the remaining quotient. This naturally builds the string left to right.
Think of it like spelling out a number in English. To say "701", you first figure out what comes before the last digit (the "ZY" case: first deal with the "Z" part, then append "Y"). The recursive call handles everything except the last character, and then we tack on the current character.
columnNumber is 0, return an empty string.columnNumber.columnNumber / 26 (the "prefix" of the result).columnNumber % 26.columnNumber by 26. The recursion depth is ceil(log_26(n)), which is at most 7 for the given constraints.