LeetCode 168. Excel 表列名称
题目描述


题意分析
输入一个正整数列号,要求输出 Excel 里对应的列标题:
1是"A",26是"Z",27是"AA",28是"AB",以此类推。
全题唯一的难点就藏在编号的起点上:A对应的是1而不是0。日常见到的进位制,每一位的取值都是从0开始的,二进制是0和1,十进制是0到9;而这套列名里每一位的合法取值是A到Z,也就是1到26,压根没有代表零的符号。正因为缺了这个零,26之后不是像十进制那样进位成「一零」,而是直接跳到AA;把它当成普通的0基进位制来写,每一位都会整体偏移一格,而且越大的输入错得越离谱。
约束信号:列号上限是2^31 - 1,说明结果最多七个字母,规模完全不是问题,也不存在需要防溢出的乘法——整个过程只有减法和除法,数值单调变小。
边界要盯住三处:1输出单个"A";26输出"Z"而不是任何两位结果;27是第一个进位的输入,输出"AA"。最大值2147483647对应"FXSHRXW",可以用来自查。
解法:减一后按 26 进制转换
核心思路
Excel 列名不是普通的 26 进制:普通进制的每位是
0..25,而 Excel 使用A..Z表示1..26,没有代表 0 的字符。若直接取columnNumber % 26,输入26会得到余数 0,无法正确表示Z。解决办法是在每轮取模前先减一,把当前位从
1..26平移到0..25:
(columnNumber - 1) % 26得到当前最低位,对应A..Z;(columnNumber - 1) / 26得到尚未处理的高位。循环不变量是:每轮开始时,
columnNumber表示尚未转换的高位列号;本轮减一、取模后确定其中最低位,再用同一个减一后的值整除 26,进入下一位。这个数严格变小,最终归零。每轮得到的是从低位到高位的字母,因此最后需要反转。该转换等价于不断提取“双射 26 进制”的最低位,减一同时修正了字母映射和进位,所以不会在
Z -> AA的边界处出错。
解题步骤
- 准备字符容器,用来按低位到高位保存结果。
- 当
columnNumber > 0时,先执行columnNumber--。- 用
columnNumber % 26得到当前字母偏移,追加'A' + offset。- 执行
columnNumber /= 26,继续处理更高位。- 反转字符序列并返回。
以
701为例:减一得700,余数24对应Y,商为26;下一轮减一得25,余数25对应Z,商为0。生成顺序是YZ,反转后得到ZY。边界26则在减一后直接得到余数25,正确输出Z。
代码实现
class Solution {
public String convertToTitle(int columnNumber) {
StringBuilder ans = new StringBuilder();
while (columnNumber > 0) {
columnNumber--;
ans.append((char) ('A' + columnNumber % 26));
columnNumber /= 26;
}
return ans.reverse().toString();
}
}
func convertToTitle(columnNumber int) string {
ans := make([]byte, 0)
for columnNumber > 0 {
columnNumber--
ans = append(ans, byte('A'+columnNumber%26))
columnNumber /= 26
}
for left, right := 0, len(ans)-1; left < right; left, right = left+1, right-1 {
ans[left], ans[right] = ans[right], ans[left]
}
return string(ans)
}
复杂度分析
- 时间复杂度:
O(log_{26} n)。循环次数等于列名长度,最后反转同样是该数量级。- 空间复杂度:
O(log_{26} n)。字符构造缓冲区与最终列名长度同阶;即使不计返回字符串,本实现仍需这段缓冲空间。
关键点总结
- 本题是没有 0 的“双射 26 进制”,不能直接套普通进制转换。
- 每轮先减一,再让取模和整除都使用减一后的值;两步必须保持同一基准。
- 取模天然从最低位开始生成字符,所以最终要反转。
- 面试时用
26 -> Z、27 -> AA解释减一,比只背模板更有说服力;反向转换则是value = value * 26 + ch - 'A' + 1。
易错点总结
- 完全不减一:
26 % 26 = 0,会把26错转成BA,而不是Z。- 只在取模时减一、整除仍用原值:
26的高位会多执行一轮,得到AZ。- 在 Java 中忘记把
'A' + offset强转为char,StringBuilder.append会追加整数值。- 忘记反转:
701的生成顺序是YZ,正确结果却是ZY。- 循环条件应为
columnNumber > 0;写成>= 0会在归零后继续处理非法的-1。
相似题目
| 题目 | 难度 | 考察点 |
|---|---|---|
| 171. Excel 表列序号 | 简单 | 本题的逆运算,改为从高位向低位累加 res * 26 + (ch - 'A' + 1)
|