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


题意分析
给定从一开始的正整数列编号,返回它对应的 Excel 列名称。列名称只使用大写字母,每一位的
A到Z表示数值1到26,超过一位能表示的范围后向更高位进位。关键区别是这里没有表示零的字母。普通二十六进制的每位范围是
0..25,不能直接把列编号取模后照搬普通进制转换。需要确定最低位的字母,以及去掉这一位后剩余的高位编号。
解法:减一后按 26 进制转换
核心思路
[!blue]
设当前编号为
N,剩余高位编号为q,最低位字母的数值为r。它们满足N = 26q + r,但这里r的范围是1..26,而普通整除的余数范围是0..25。将等式两边减一,得到
N - 1 = 26q + (r - 1)。此时r - 1正好落在0..25,所以(N - 1) % 26就是当前字母相对A的偏移,(N - 1) / 26就是剩余高位编号。减一不是单独修正某个边界,而是把整套数位规则转换到普通整除能处理的范围。每次剥掉一个最低位后,高位部分仍然使用同样的列名规则,因此每轮都要先减一,再用减一后的值取模和整除。不能只在最初减一次,也不能取模用新值、整除却用旧值。
生成字符的顺序是从最低位到最高位,追加到缓冲区后需要整体反转。编号变成零时说明高位已经全部处理完,循环结束。
解题步骤
- 创建字符缓冲区,用来按低位到高位保存字母。
- 当
columnNumber > 0时,先将它减一。- 用
columnNumber % 26得到0..25的偏移,追加对应的大写字母。- 用
columnNumber /= 26去掉已经处理的最低位,继续处理高位。- 反转缓冲区并返回字符串。
代码实现
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(d),其中d为结果列名的字符数。每轮生成一个字母,最后反转也遍历d个字符。- 空间复杂度:
O(d),保存字符缓冲区和结果字符串。
关键点总结
[!green]
- 先写出
N = 26q + r、1 <= r <= 26,就能自然推导出每轮减一的原因。- 减一后的商和余数分别表示高位编号与当前字母偏移,二者必须使用同一个调整后的数值。
- 逐次取模得到的是逆序字符,输出前需要反转。
易错点总结
[!yellow]
- 按普通进制直接取模:零余数对应的应当是本位的
Z,而不是另一个零数位;先减一可统一处理。- 只调整余数、不调整商:最低位得到字母后,高位仍可能多保留一次进位,必须在取模和整除前共同减一。
- 只在循环外减一:高位也使用
1..26的规则,每处理一位都需要重新调整。- Java 不转为
char:'A' + offset是整数表达式,直接追加会调用追加整数的方法。- 忘记反转或在归零后继续循环:前者会颠倒位序,后者会处理不存在的高位。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 171. Excel 表列序号 | 简单 | 互为转换方向,本题需要处理没有零数码的26进制,取余前先减一。 |
| 补充题 145. 有符号整数的进制转换 | 中等 | 同样反复除基数生成数位,但普通进制有0,Excel列名用1到26表示字母。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!