这一题真的只是烦而已。。。
这题的关键就是要看出英语算数字是每三个数一组的。
譬如说这个数:1,234,567。就是1 million 234 thousand 567这样。
再往下细谈,就是 "one" million "two hundred thirty four" thousand "five hundred sixty seven"
又或者说:1,234,567,890。就是1 billion 234 million 567 thousand 890
往下细谈, 就是 "one" billion "two hundred thirty four" million "five hundred sixty seven" thousand "eight hundred ninety"
然后呢,每一组三个数字,每一位就需要分开处理。譬如,234,就是200 + 30 + 4 就是 two hundred + thirty + four。
当然,十位数和个位数的组合也是有特例的,就是11 ~ 19和0, 其中0是不需要翻译的,也就是200是不需要翻译成 two hundred + zero + zero的,一个two hundred就完事了。至于11到19,是特别的字符串,eleven啊,twelve啊,thirteen啊。。而不是10 + 3 = ten + three这个样子,所以也要特别处理。
所以做法其实很简单,我们就要有几个mapping。第一个是0 到 19 的mapping,用来应付十位数和个位数为0 ~ 19的特别情况。第二个是20, 30, ... 90的mapping,这个就是20 ~ 90 在十位数上的名称mapping。 第三个就是1000, 1000000, 1,000,000,000的mapping,就是每三个一组的mapping,因为input是保证在整型数的范围的,所以最大不会超过billion的级别。
有了这些mapping之后就很简单了,每次求模1000,得到0 ~ 999的范围,然后进行分析,百位数有的话就有,否则直接略过。然后0 ~ 99的范围也根据上面表述的进行翻译。一个特殊情况就是如果这一组是0的话,就直接跳过thousand million或者billion,也就是表示这一组不输出任何字符串。举个例子,1000000就是one million,你不会说one million zero thousand zero这样。但是,还有一个最终特例,那就是0,遇到0就直接输出Zero,上面那套是不管用的。根据上面的描述,可以得到代码如下:
public String numberToWords(int num) {
if (num == 0) return "Zero";
String[] numStrMap = {
"Zero",
"One",
"Two",
"Three",
"Four",
"Five",
"Six",
"Seven",
"Eight",
"Nine",
"Ten",
"Eleven",
"Twelve",
"Thirteen",
"Fourteen",
"Fifteen",
"Sixteen",
"Seventeen",
"Eighteen",
"Nineteen"
};
String[] tenStrMap = {
"",
"Twenty",
"Thirty",
"Forty",
"Fifty",
"Sixty",
"Seventy",
"Eighty",
"Ninety"
};
String[] quarMap = {
"",
"Thousand",
"Million",
"Billion"
};
Stack<String> strStk = new Stack<>();
StringBuilder builder = new StringBuilder();
int quarNum = 0;
while (num > 0) {
int curPart = num % 1000;
if (curPart > 0) {
strStk.push(quarMap[quarNum]);
int tenPart = curPart % 100;
if (tenPart > 0) {
if (tenPart < 20) {
strStk.push(numStrMap[tenPart]);
} else {
int single = tenPart % 10;
if (single > 0) {
strStk.push(numStrMap[single]);
}
strStk.push(tenStrMap[tenPart / 10 - 1]);
}
}
if (curPart >= 100) {
strStk.push("Hundred");
strStk.push(numStrMap[curPart / 100]);
}
}
num /= 1000;
quarNum++;
}
while (!strStk.isEmpty()) {
builder.append(strStk.pop());
if (!strStk.isEmpty() && !strStk.peek().equals("")) {
builder.append(' ');
}
}
return builder.toString();
}
看得出来这题就是烦,case分支很多,special cases也有几个。那几个mapping特别长。真正算法部分的代码大约就是30多行。