LeetCode 面试题 16.08. 整数的英语表示
题目描述

题意分析
将非负 32 位整数转换为英文表示。单词间只保留一个空格,不加
and;整个数字为零时返回Zero,其他数字内部的零位或零分组不单独读出。英文数量级每三位递进一次,从高到低为
Billion、Million、Thousand和没有单位的个位组。利用这个结构,可以把整个转换拆成“确定各组数量级”和“转换三位以内的数”两部分。不能简单逐位翻译,因为
10到19有独立词形,整十也有专门名称。将这些固定词形放进查找表后,每个三位组只需拆成百位、十位与个位。
解法:三位一组递归转换
核心思路
[!blue]
外层的
num表示尚未转换的低位部分。按10^9、10^6、10^3、1依次处理:用除法取出当前组value,转换后追加对应单位,再用取模去掉这一组。每处理完一个数量级,剩余值都小于它,下一个组便不会超过三位;最高的十亿组在本题范围内也只有一位。当前组为零时直接跳过,不输出组内容或单位。此时
num本来就小于当前数量级,所以不执行取模也不会改变余下部分。外层只处理非零组,唯一会被全部跳过的整体零由入口单独返回Zero。
convert与 Go 的convertNumber只处理0..999。输入为零时返回空串;小于20时直接查特殊词形表;小于100时读取整十名称,再转换个位余数;其余情况先读取百位数字和Hundred,再转换余下两位。每次递归只保留更小的余数,最终一定落到查表或零的分支。组内的零返回空串,表示后面已经没有要读的部分,而不是再补一个
Zero。Java 用组内的trim去掉空余数留下的尾空格,外层appendPart只在两个非空片段间加一个空格;Go 则只收集非空片段,用strings.Join统一连接。每个非零三位组都被准确转换,并且按从高到低的顺序附上对应数量级;零组不贡献文字,因此拼接结果既保持原数的数值结构,也符合题目的空格格式。
解题步骤
num == 0时直接返回Zero。- 按
{10^9, 10^6, 10^3, 1}从高位取出当前三位组value = num / VALUES[i]。value != 0时,将它转为三位以内的英文,并追加对应的UNITS[i];随后用取模去掉已处理部分。- 三位转换中依次处理
< 20、< 100、< 1000三种情况,最后用单个空格连接所有片段。整百、整十会产生零余数,转换函数返回空串即可终止,不会增加多余单词。中间出现零组时只跳过该组,仍继续检查更低数量级。非负 32 位整数最多用到
Billion,当前四个数量级足以覆盖全部输入。
代码实现
// 从 Billion 到个位组三位一组处理,每组只需转换 0..999。
class Solution {
private static final String[] LESS_THAN_20 = {
"",
"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[] VALUES = {
1000000000,
1000000,
1000,
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 < VALUES.length; i++) {
int value = num / VALUES[i];
if (value == 0) {
continue;
}
appendPart(answer, convert(value));
appendPart(answer, UNITS[i]);
num %= VALUES[i];
}
return answer.toString().trim();
}
private String convert(int num) {
if (num == 0) {
return "";
}
if (num < 20) {
return LESS_THAN_20[num];
}
if (num < 100) {
return (TENS[num / 10] + " " + convert(num % 10)).trim();
}
return (LESS_THAN_20[num / 100] + " Hundred " + convert(num % 100)).trim();
}
private void appendPart(StringBuilder builder, String part) {
if (part.isEmpty()) {
return;
}
if (builder.length() > 0) {
builder.append(' ');
}
builder.append(part);
}
}
import "strings"
// 从 Billion 到个位组三位一组处理,每组只需转换 0..999。
func numberToWords(num int) string {
if num == 0 {
return "Zero"
}
values := []int{
1000000000,
1000000,
1000,
1,
}
units := []string{
"Billion",
"Million",
"Thousand",
"",
}
parts := []string{}
for i, value := range values {
cur := num / value
if cur == 0 {
continue
}
parts = append(parts, convertNumber(cur))
if units[i] != "" {
parts = append(parts, units[i])
}
num %= value
}
return strings.Join(parts, " ")
}
func convertNumber(num int) string {
lessThan20 := []string{
"",
"One",
"Two",
"Three",
"Four",
"Five",
"Six",
"Seven",
"Eight",
"Nine",
"Ten",
"Eleven",
"Twelve",
"Thirteen",
"Fourteen",
"Fifteen",
"Sixteen",
"Seventeen",
"Eighteen",
"Nineteen",
}
tens := []string{
"",
"",
"Twenty",
"Thirty",
"Forty",
"Fifty",
"Sixty",
"Seventy",
"Eighty",
"Ninety",
}
if num == 0 {
return ""
}
if num < 20 {
return lessThan20[num]
}
if num < 100 {
parts := []string{
tens[num/10],
}
if num%10 != 0 {
parts = append(parts, convertNumber(num%10))
}
return strings.Join(parts, " ")
}
parts := []string{
lessThan20[num/100],
"Hundred",
}
if num%100 != 0 {
parts = append(parts, convertNumber(num%100))
}
return strings.Join(parts, " ")
}
复杂度分析
- 时间复杂度:$O(1)$,本题固定为 32 位整数,至多处理四个三位组,每组递归与输出长度均有常数上界。
- 空间复杂度:$O(1)$,查找表、分组数、递归深度以及结果长度都受固定整数范围限制。
关键点总结
[!green]
- 三位分组是结构核心:外层负责数量级,内层只负责 $0$ 到 $999$ 的读法。
0有两种语义:整个数字为零时输出Zero,分组内部为零时输出空串并跳过该组。- $10$ 到 $19$ 必须单独查表,不能套用整十位规则。
- Java 跳过空片段并在追加前补分隔空格,Go 收集非空片段后连接,两者都保证单词间只有一个空格。
易错点总结
[!yellow]
- 为零分组输出
Zero:只有整个输入为零才读作Zero,非零数字内部的零组应跳过。- 按整十加个位拼出
10到19:这一范围使用独立词形,必须直接查表。- 忘记处理整体为零:通用分组逻辑会得到空串,所以
num == 0必须单独返回Zero。- 边拼接边无条件加空格:容易出现连续空格或尾空格;应只追加非空片段并统一连接。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 12. 整数转罗马数字 | 中等 | 同样按数值区段输出规范表示,原题使用罗马数字,本题按三位数量级和英语词形转换。 |