如何把 Excel 列标题转换成列序号?(LeetCode 171)
简化版
Excel 列标题本质是 26 进制,但没有数字 0:A=1,B=2,…,Z=26,AA=27。从左到右扫描字符串,每次把当前结果乘以 26,再加当前字符对应的值。
例如 AB:先得到 1,再计算 1 * 26 + 2 = 28。所以答案是 28。时间复杂度 O(n),空间复杂度 O(1)。
详细版
int titleToNumber(String columnTitle) {
int ans = 0;
for (int i = 0; i < columnTitle.length(); i++) {
int value = columnTitle.charAt(i) - 'A' + 1;
ans = ans * 26 + value;
}
return ans;
}
它和普通进制转换很像:十进制 "123" 是 ((1)*10 + 2)*10 + 3,Excel 标题 "ABC" 是 ((1)*26 + 2)*26 + 3。差异在于字符值从 1 开始,而不是从 0 开始。
完整版教学
一、Excel 列标题为什么像进制
Excel 列从 A 到 Z,再到 AA、AB。这和数字进位很像:单个位置有 26 种可能,超过 Z 后向左增加一位。
A -> 1
B -> 2
...
Z -> 26
AA -> 27
AB -> 28
因此可以把它看成一种特殊的 26 进制表示。
二、和普通 26 进制的区别
普通 26 进制通常有 0..25,但 Excel 没有 0,A 直接表示 1,Z 表示 26。这叫“一基计数”。
| 字符 | Excel 值 | 普通 0 基想象 |
|---|---|---|
| A | 1 | 0 |
| B | 2 | 1 |
| Z | 26 | 25 |
所以字符映射必须写成:
int value = c - 'A' + 1;
如果漏掉 +1,所有结果都会偏小。
三、从左到右累积公式
对于任意进制,从左到右读入新位时,旧结果要先乘以进制,再加新位值。
ABC
初始 ans = 0
读 A: ans = 0 * 26 + 1 = 1
读 B: ans = 1 * 26 + 2 = 28
读 C: ans = 28 * 26 + 3 = 731
最终 ABC 对应 731。
四、为什么不是从右往左更简单
从右往左也能做,需要维护权重 1, 26, 26^2...。从左往右更简洁,因为它不需要额外变量记录权重,只用一个 ans 就能完成。
左到右: ans = ans * 26 + value
右到左: ans += value * weight; weight *= 26
面试里推荐左到右写法,更短也更不容易错。
五、边界和溢出讨论
LeetCode 171 的输入通常保证结果在 32 位整数范围内。但工程扩展中,如果列标题长度非常长,ans * 26 可能溢出,需要改用 long 或大整数。
只要看到
ans = ans * base + digit,就要想到上界溢出;面试题可按题目约束处理,但最好主动说明。
六、和反向题的关系
反向题是“列序号转列标题”。那道题要特别处理 n--,因为 Excel 是一基计数;本题则更直接,只需要把字符映射成 1..26。
| 题型 | 核心难点 |
|---|---|
| 标题转数字 | A=1,按 26 进制累积 |
| 数字转标题 | 先减 1 再取模,处理无 0 进制 |
理解这一对题,可以帮助你掌握一基进制和普通进制的差异。
七、面试现场如何验证
建议用这些样例手推:
A -> 1Z -> 26AA -> 27AB -> 28ZY -> 701ABC -> 731
这些样例覆盖单字符、进位后第一项、多字符累积和末尾大字符。
八、常见误区与追问
- 误区:把 A 当成 0。 Excel 列标题没有 0,A 应该映射为 1。
- 误区:忘记每读一位都乘以 26。 多字符时高位权重会丢失。
- 误区:用
Math.pow从右往左算。 浮点幂可能带来不必要的精度和类型问题。 - 误区:只处理单字符标题。
AA才是本题真正考点。 - 追问:为什么
AA是 27 不是 26? 因为Z已经占了 26,下一列进位到AA。 - 追问:反向转换为什么要先减 1? 因为反向题要把一基计数转成普通取模位置。
九、加强记忆
- Excel 列标题是没有 0 的 26 进制。
- 字符值是
c - 'A' + 1。 - 从左到右公式是
ans = ans * 26 + value。 AA=27是最重要的进位样例。- 反向题要先减 1,本题只要正常累积。