LeetCode 273. 整数转换英文表示
题目描述

题意分析
将一个非负整数转换成规范的英文数字表示,返回字符串。输入范围是
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,避免把零组和整个数字为零混淆。所有词通过同一个追加函数写入结果:已有内容时先添加一个空格,再写入当前词;首次写入不加空格,词后也不加空格。因为只传入真正需要的非空单词,最终不会产生首尾空格或连续空格。
解题步骤
- 输入为零时返回
Zero。- 按从大到小的四个量级,用除法取出当前组。
- 当前组非零时,依次处理百位、整十位和不足二十的剩余值,再追加非空的量级词。
- 用取模移除当前组,继续处理较低量级。
- 所有单词均由统一追加函数连接,最后返回结果字符串。
代码实现
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. 整数转罗马数字 | 中等 | 同样把整数分块转换为规范文本,罗马数字按符号值分解,本题按千进位和三位组处理。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!