目录

题目描述

168. Excel 表列名称

image-20230306222859787

image-20230306222856487

题意分析

输入一个正整数列号,要求输出 Excel 里对应的列标题:1"A"26"Z"27"AA"28"AB",以此类推。
全题唯一的难点就藏在编号的起点上:A 对应的是 1 而不是 0。日常见到的进位制,每一位的取值都是从 0 开始的,二进制是 01,十进制是 09;而这套列名里每一位的合法取值是 AZ,也就是 126,压根没有代表零的符号。正因为缺了这个零,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 的边界处出错。

解题步骤

  1. 准备字符容器,用来按低位到高位保存结果。
  2. columnNumber > 0 时,先执行 columnNumber--
  3. columnNumber % 26 得到当前字母偏移,追加 'A' + offset
  4. 执行 columnNumber /= 26,继续处理更高位。
  5. 反转字符序列并返回。

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 -> Z27 -> AA 解释减一,比只背模板更有说服力;反向转换则是 value = value * 26 + ch - 'A' + 1

易错点总结

  • 完全不减一:26 % 26 = 0,会把 26 错转成 BA,而不是 Z
  • 只在取模时减一、整除仍用原值:26 的高位会多执行一轮,得到 AZ
  • 在 Java 中忘记把 'A' + offset 强转为 charStringBuilder.append 会追加整数值。
  • 忘记反转:701 的生成顺序是 YZ,正确结果却是 ZY
  • 循环条件应为 columnNumber > 0;写成 >= 0 会在归零后继续处理非法的 -1

相似题目

题目 难度 考察点
171. Excel 表列序号 简单 本题的逆运算,改为从高位向低位累加 res * 26 + (ch - 'A' + 1)