题目描述

✅ 273. 整数转换英文表示

image-20260928235139331

题意分析

将一个非负整数转换成规范的英文数字表示,返回字符串。输入范围是 0 到 2^31 - 1,需要覆盖十亿量级;英文单词首字母大写,单词之间只用一个空格,不加首尾空格、逗号、连字符或 And。

整个数为零时输出 Zero。非零数内部某些位或某个三位组为零时,不额外读出零,也不能只输出没有对应数值的量级词。要转换的是整数的数值含义,而不是逐个翻译它的十进制数字。

解法:三位分组 + 组内查表

核心思路

[!blue]

英文整数每三位提升一个量级,依次为个位组、Thousand、Million、Billion。因此只需解决小于一千的整数如何读,再给非零组追加所属量级词,按高位到低位拼起来。

代码按 10^9、10^6、10^3、1 依次处理。对当前量级 scale,整数除法 num / scale 取出该组三位,随后用 num %= scale 去掉已处理部分。更高位已经移除,当前组自然小于一千;输入上界也保证最高的十亿组足够小。

组内先处理百位:商给出百位数字,追加对应英文和 Hundred,余数保留最后两位。若剩余数至少为二十,再读整十位并保留个位;否则直接查 1 到 19 的词表。这些专用拼写不能靠统一后缀生成,尤其十到十九应当作为整体读取。

某组为零时,组内数字和它的量级词一起跳过。组内已经读完百位或整十位后,剩余为零也无需追加任何词。只有整个输入为零时才单独返回 Zero,避免把零组和整个数字为零混淆。

所有词通过同一个追加函数写入结果:已有内容时先添加一个空格,再写入当前词;首次写入不加空格,词后也不加空格。因为只传入真正需要的非空单词,最终不会产生首尾空格或连续空格。

解题步骤

  1. 输入为零时返回 Zero。
  2. 按从大到小的四个量级,用除法取出当前组。
  3. 当前组非零时,依次处理百位、整十位和不足二十的剩余值,再追加非空的量级词。
  4. 用取模移除当前组,继续处理较低量级。
  5. 所有单词均由统一追加函数连接,最后返回结果字符串。

代码实现

class Solution {
    private static final String[] BELOW_TWENTY = {
        "",
        "One",
        "Two",
        "Three",
        "Four",
        "Five",
        "Six",
        "Seven",
        "Eight",
        "Nine",
        "Ten",
        "Eleven",
        "Twelve",
        "Thirteen",
        "Fourteen",
        "Fifteen",
        "Sixteen",
        "Seventeen",
        "Eighteen",
        "Nineteen"
    };
    private static final String[] TENS = {
        "",
        "",
        "Twenty",
        "Thirty",
        "Forty",
        "Fifty",
        "Sixty",
        "Seventy",
        "Eighty",
        "Ninety"
    };
    private static final int[] SCALES = {
        1_000_000_000,
        1_000_000,
        1_000,
        1
    };
    private static final String[] UNITS = {
        "Billion",
        "Million",
        "Thousand",
        ""
    };

    public String numberToWords(int num) {
        if (num == 0) {
            return "Zero";
        }

        StringBuilder answer = new StringBuilder();

        // 较大量级取走后,下一小节不足一千;零小节连量级词一起跳过。
        for (int i = 0; i < SCALES.length; i++) {
            int group = num / SCALES[i];

            if (group != 0) {
                appendBelowThousand(answer, group);

                if (!UNITS[i].isEmpty()) {
                    appendWord(answer, UNITS[i]);
                }
            }

            num %= SCALES[i];
        }

        return answer.toString();
    }

    private void appendBelowThousand(StringBuilder answer, int num) {
        if (num >= 100) {
            appendWord(answer, BELOW_TWENTY[num / 100]);
            appendWord(answer, "Hundred");
            num %= 100;
        }

        if (num >= 20) {
            appendWord(answer, TENS[num / 10]);
            num %= 10;
        }

        // 百位和整十已经取走,剩余小于二十的数按完整词表读取。
        if (num > 0) {
            appendWord(answer, BELOW_TWENTY[num]);
        }
    }

    // 只在已有内容后添加一个空格,统一避免首尾与连续空格。
    private void appendWord(StringBuilder answer, String word) {
        if (answer.length() > 0) {
            answer.append(' ');
        }

        answer.append(word);
    }
}
import "strings"

var belowTwenty = []string{
    "",
    "One",
    "Two",
    "Three",
    "Four",
    "Five",
    "Six",
    "Seven",
    "Eight",
    "Nine",
    "Ten",
    "Eleven",
    "Twelve",
    "Thirteen",
    "Fourteen",
    "Fifteen",
    "Sixteen",
    "Seventeen",
    "Eighteen",
    "Nineteen",
}

var tensWords = []string{
    "",
    "",
    "Twenty",
    "Thirty",
    "Forty",
    "Fifty",
    "Sixty",
    "Seventy",
    "Eighty",
    "Ninety",
}

func numberToWords(num int) string {
    if num == 0 {
        return "Zero"
    }

    scales := []int{
        1_000_000_000,
        1_000_000,
        1_000,
        1,
    }
    units := []string{
        "Billion",
        "Million",
        "Thousand",
        "",
    }
    var answer strings.Builder

    // 较大量级取走后,下一小节不足一千;零小节连量级词一起跳过。
    for i, scale := range scales {
        group := num / scale
        if group != 0 {
            appendBelowThousand(&answer, group)
            if units[i] != "" {
                appendWord(&answer, units[i])
            }
        }
        num %= scale
    }
    return answer.String()
}

func appendBelowThousand(answer *strings.Builder, num int) {
    if num >= 100 {
        appendWord(answer, belowTwenty[num/100])
        appendWord(answer, "Hundred")
        num %= 100
    }
    if num >= 20 {
        appendWord(answer, tensWords[num/10])
        num %= 10
    }
    // 百位和整十已经取走,剩余小于二十的数按完整词表读取。
    if num > 0 {
        appendWord(answer, belowTwenty[num])
    }
}

// 只在已有内容后添加一个空格,统一避免首尾与连续空格。
func appendWord(answer *strings.Builder, word string) {
    if answer.Len() > 0 {
        answer.WriteByte(' ')
    }
    answer.WriteString(word)
}

复杂度分析

  • 时间复杂度:本题为 $O(1)$,32 位非负整数最多分成四组,每组最多输出固定数量的单词。若推广到任意十进制位数 d,分组处理与输出规模均为 $O(d)$。
  • 空间复杂度:不计返回字符串为 $O(1)$,只使用固定词表、量级表和常数个变量;推广到 d 位时,输出本身占 $O(d)$。

关键点总结

[!green]

  • 三位组内部使用相同读法,组与组之间只需区分量级词。
  • 每次取组后移除高位,保证下一轮读取的仍是一个独立小组。
  • 零组整体跳过,真正的零输入单独处理;空格由一个出口统一管理。

易错点总结

[!yellow]

  • 将十到十九拆成普通十位与个位,会得到错误的英文读法,应直接查专用词表。
  • 当前组为零仍追加量级词,会输出没有数值支撑的 Thousand 或 Million。
  • 从低位开始取组,却直接把结果追加到尾部,会颠倒量级顺序。
  • 没有处理 Billion,会漏掉合法输入的最高量级。
  • 每个单词后都手动添加空格,容易留下多余尾空格;这里在已有内容之后、下一个词之前添加分隔符。
  • 处理完一个量级后忘记对 num 取模,后续组会混入已翻译的高位。

相似题目

题目 难度 关联与区别
12. 整数转罗马数字 中等 同样把整数分块转换为规范文本,罗马数字按符号值分解,本题按千进位和三位组处理。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/38664061
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!