题目链接:https://leetcode-cn.com/problems/integer-to-english-words/
分类:
数学(给定数字转英文的规则、数字分组转换:从最低位开始每3位分成一组进行转换)字符串(设置字符串数组:THOUSAND,LESS_THAN_TWENTY,HUNDRED作为字典数组、转换细节:空格符的处理)理解转换规则: int型最大数是:2,147,483,647,共10位。 整个数字可以按逗号划分为多个部分,每个部分都按三位数进行英文转换:
例如 147:One Hundred Forty Seven,最后再在后面加上量级:One Hundred Forty Seven Million三位数中含0时的转换:
例如 103:one hundred three,而不是one hundred and three转换前所需要的准备:
为了转换方便,我们先将0~19,每个整十,三个量级都预先存放在数组中,作为字典数组供查询使用:
private final String[] THOUSAND = {"", "Thousand", "Million", "Billion"}; private final String[] LESS_THAN_TWENTY = {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"}; private final String[] HUNDRED = {"", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"};其中,LESS_THAN_TWENTY数组存放的是0~19对应的英语,且0对应的是空字符串""; 同理HUNDRED数组中0和10对应的英语也设置为空字符串,因为10对应的ten已经在 LESS_THAN_TWENTY中了。
转换的具体流程:
对整个数字我们可以分为多个部分来处理,例如:2,147,483,647 从最低位开始每3位数分为一组,可以分为4个分组,每个分组最多3位数字,分组的内部处理都是相同的,内部处理结束后返回对应的英文字符串,将这4个分组对应的英文字符串组合起来,就能得到最终的转换结果。
从整体上看,我们每次处理的分组就是num的最低3位(即 num % 1000),然后将num的int形式向右移动3位(即num / 1000),再处理当前num的最低3位,直到num == 0。
在最终转换结果res中,越先处理的3位数字得到的英文字符串在res中排在越后面:
例如:num = 2,147,483,647 最先处理num的低3位647(num % 1000),得到"Six Hundred Forty Seven",res="Six Hundred Forty Seven" num右移3位:num / 1000 = 2 147 483 接着处理num的低3位483,得到"Four Hundred Eighty Three Thousand",需要前插到res的首部,即res="Four Hundred Eighty Three Thousand Six Hundred Forty Seven" ...以此类推。因此,我们需要使用StringBuilder的insert函数,将当前分组得到的英文字符串前插到res的0下标处:
res.insert(0, str);//向res的首部插入str分组内部处理helper函数: 先开辟一个StringBuilder来存放分组转换的英语字符串;
例如:2,147,483,647最先处理的分组是num = 647,我们从百位到个位依次处理:
第一阶段:获取百位上的数值:647/100=6,因为可能存在047这种百位为0的情况,所以只有百位数值 > 0才对百位做进一步处理:
将百位数值6转换成英语(通过LESS_THAN_TWENTY[6]获取),接着加上" Hundred "(注意Hundred前后的空格符不能省略);将647去除百位:num = 647 % 100 = 47,进入下一阶段;第二阶段:处理此时的num:
如果num >= 20,则模仿百位对十位做进一步处理: 将num的十位数值4(num/10=4)转换成英语(通过HUNDRED[4]获取"Forty");将47去除十位:num = 47 % 10 = 7,进入第三阶段; 如果num < 20,则直接进入第三阶段:第三阶段:将此时的num=7转换成英语(通过LESS_THAN_TWENTY[7]获取);
最后,在生成的英语字符串末尾加上量级对应的英语:
647对应的量级是0,字符串末尾不需要加任何量级,所以把THOUSAND[0]设置为空字符串"";484对应的量级是1,字符串末尾要加上"Thousand";147对应的量级是2,字符串末尾要加上"Million";2对应的量级是3,字符串末尾要加上"Billion"。除了上述的主要流程,内部处理还有需要注意的细节:
如果需要转换的三位数全为0,则直接转换成空字符串,不需要将0转换成英语,也不需要加量级,
例如:1000000 输出:"One Million",前两个000都只转换成空字符串。百位的"Hundred"之后、十位的英语之后、个位的英语之后、量级的英语之后都记得加上空格符,但这样可能导致整个num转换成英语字符串时末尾可能有多余的空格符,所以在返回最终结果前将尾部的空格符去掉:trim()。
实现代码:
class Solution { private final String[] THOUSAND = {"", "Thousand", "Million", "Billion"}; private final String[] LESS_THAN_TWENTY = {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"}; private final String[] HUNDRED = {"", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"}; public String numberToWords(int num) { //特殊用例 if(num == 0) return "Zero"; //level用于记录当前三位数所在的量级(level=1:"Thousand", =2:"Million", =3:"Billion") int level = 0; //res存放数字num转换的英语字符串 StringBuilder res = new StringBuilder(); //每次处理num的低3位,然后将num右移3位,直到num==0 while(num != 0){ //获取当前num的低3位转换的英文字符串 String part = helper(num % 1000, level); //将转换的英文前插到res首部(insert的使用是关键) res.insert(0, part); //每处理完3位数字,量级+1 level++; //num的int型右移3位 num /= 1000; } //最后返回前要去除首尾可能存在的空格符 return res.toString().trim(); } //对每部分(最多3位数字)做内部处理,返回该部分对应的英文,level表示num这三位数所在的量级 public String helper(int num, int level){ StringBuilder sb = new StringBuilder(); //如果num为0,则直接返回空字符串 if(num == 0) return sb.toString(); //如果num的百位不为0,则做百位数值的转换 if(num / 100 > 0) { sb.append(LESS_THAN_TWENTY[num / 100]).append(" Hundred "); num %= 100; } //如果此时num >= 20,则对十位数值做转换,然后提取num的个位数 if(num >= 20){ sb.append(HUNDRED[num / 10]).append(" "); num %= 10;//获取num的个位数 } //如果此时num < 20,则直接做英文转换 if(num > 0){ sb.append(LESS_THAN_TWENTY[num]).append(" "); } //最后在英文字符串末尾加上当前num所在的量级的英文 sb.append(THOUSAND[level]).append(" "); return sb.toString(); } }