从一读到一亿需要读多少个汉字?

  • 题目分析
  • 思路分析
  • 方法改进
    • 具体思路
    • 完整代码
    • 缺点
  • 请教

题目分析

  首先对读法做一下规范,我是做过两年审计工作,所以习惯于采用会计的大写方式
  例如(没有测试所有格式,仅测试了如下个别代表性数据;这里的十均表示为"壹拾",间隔有零均读零):

数据 大写 数据 大写 数据 大写
1 10,100 壹萬零壹佰 110,110 壹拾壹萬零壹佰壹拾
10 壹拾 11,000 壹萬壹仟 111,001 壹拾壹萬壹仟零壹
100 壹佰 11,100 壹萬壹仟壹佰 1,000,000 壹佰萬
101 壹佰零壹 11,010 壹萬壹仟零壹拾 1,001,000 壹佰萬零壹仟
110 壹佰壹拾 10,110 壹萬零壹佰壹拾 1,100,101 壹佰壹拾萬零壹佰零壹
111 壹佰壹拾壹 111,011 壹拾壹萬壹仟零壹拾壹 1,100,101 壹佰壹拾萬零壹佰零壹
1,000 壹仟 110,111 壹拾壹萬零壹佰壹拾壹 1,101,100 壹佰壹拾萬零壹仟壹佰
1,001 壹仟零壹 101,111 壹拾萬零壹仟壹佰壹拾壹 1,110,100 壹佰壹拾壹萬零壹佰
1,010 壹仟零壹拾 100,010 壹拾萬零壹拾 1,111,000 壹佰壹拾壹萬壹仟
1,100 壹仟壹佰 100,100 壹拾萬零壹佰 10,010,000 壹仟零壹萬
1,011 壹仟零壹拾壹 101,000 壹拾萬零壹仟 10,100,001 壹仟零壹拾萬零壹
1,110 壹仟壹佰壹拾 110,000 壹拾壹萬 11,000,000 壹仟壹佰萬
1,101 壹仟壹佰零壹 100,011 壹拾萬零壹拾壹 10,010,001 壹仟零壹萬零壹
1,111 壹仟壹佰壹拾壹 100,101 壹拾萬零壹佰零壹 10,011,001 壹仟零壹萬壹仟零壹
10,100 壹萬零壹佰 101,001 壹拾萬壹仟零壹 10,010,100 壹仟零壹萬零壹佰

思路分析

  本来想采用列举的方式一个一个写出来,就像下面这样:

public static void main(String[] args) {int count = 0;int plus;//此处计算的是1-10,因为这些数字每个都是一个汉字;for (int i = 1; i <= 10; i++) {count += 1;}//此处计算的是11-20,因为这些数字每个都是两个汉字;for (int i = 11; i <= 20; i++) {count += 3;}//此处计算的是21-99,因为这些数字只要能被十整除,均是两个汉字(例如:二十,三十);只要不能被十整除,均是三个汉字(例如:二十三,四十七,九十九);//这是还比较简单,不需要调用找零的个数方法;for (int i = 21; i <= 99; i++) {plus = i % 10 == 0 ? 2 : 3;count += plus;}//此处计算的是100-999,此项比较麻烦,总体分为三种:// 两个汉字(例如:三百,四百),他们的特点是整百整千,能够被100整除;// 四个汉字(例如:二百零七,三百一十),他们的特点是含零,且只有一个零,种类较多,可以先看五个汉字的,然后剩下的都是四个汉字;// 五个汉字(一百二十三,九百九十九),他们的特点是不含零;for (int i = 100; i <= 999; i++) {if (i % 100 == 0) {plus = 2;} else if (findZero(i) == 0) {plus = 5;} else {plus = 4;}count += plus;}//此处计算的是1000-9999,从此处就开始往下麻烦,总体分为五种:// 两个汉字(例如:两千,五千),他们的特点是整千整万,能够被1000整除;// 四个汉字(例如:三千零一,一千一百,三千二百),他们的特点是去掉个位,可以被10整除,并且自己不能被十整除(例如:一千一百零一虽然满足去个位可被十整除,但是它有五位);// 五个汉字(例如:一千零一十),他们的特点是,在前两者判断完成的前提下,自己能够被10整除,并且去掉两位也可以被10整除;// 六个汉字(例如:一千七百三十,九千一百零一,一千零五十二),种类较多,可以先看七个汉字的,然后剩下的都是六个汉字;// 七个汉字(例如:一千三百五十七),他的特点是,不含零,可以调用findZero的方法来进行计数;for (int i = 1000; i <= 9999; i++) {//此处括号里的(i % 1000 == 0)判定条件也可以替换为(findZero(i) == 3)if (i % 1000 == 0) {plus = 2;} else if ((i % 10 != 0) && i / 10 % 10 == 0) {plus = 4;} else if ((i % 10 == 0) && i / 100 % 10 == 0) {plus = 5;} else if (findZero(i) == 0) {plus = 7;} else {plus = 6;}count += plus;}System.out.println(count);}

  就像上面一样,直接卡在了一万以下,况且无法对随意数据进行取值,所以采用了另一种方法:即先进行大写转换,然后利用统计转换后的大写读法字符的长度来进行统计.

方法改进

具体思路

  首先,最重要的是创建一种方法来把读法完成,即两种:一种是阿拉伯直接转换的数字(7→柒,0→零),另一种是位数(个十百千万,其中个不用读),所以先创建两个数组(下图为改进过的,万比较特殊,万前和万后读法相近,可以调用方法,所以把万字单独列出来)

        char[] num = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};char[] digit = {'拾', '佰', '仟'};char[] digitHuge = {'萬'};

  先创建方法来对两种读法进行分割:
  下面代码的方法是对数字进行转化:

private static String getBigNumber(int numberR) {int number = numberR;char[] num = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};String sNumber = String.valueOf(number);char[] arr = sNumber.toCharArray();char[] arr2 = new char[arr.length];for (int i = 0; i < arr.length; i++) {arr2[i] = num[Integer.parseInt(String.valueOf(arr[i]))];}StringBuffer str = new StringBuffer();for (char s : arr2) {str.append(s);}String numberBig = str.toString();return numberBig;}

下面代码的方法是对"位"进行转化:

private static String getDigit(int numberR) {int number = numberR;char[] digit = {'拾', '佰', '仟'};String sNumber = String.valueOf(number);char[] arr = sNumber.toCharArray();char[] arr2 = new char[arr.length - 1];for (int i = 0; i < arr.length - 1; i++) {arr2[i] = digit[i];}StringBuffer str = new StringBuffer();for (char s : arr2) {str.append(s);}String digitDo = str.toString();return digitDo;}

  然后就采用穿法取元素的方法进行拼接(比如三千五百零拾六–之后会对读法进行优化,现在先进行简单的拼接):

private static String nameChinese(int n) {String bigNumber = getBigNumber(n);char[] nnn = bigNumber.toCharArray();String digit = getDigit(n);char[] ddd = digit.toCharArray();String sA = String.valueOf(n);char[] arrA = sA.toCharArray();char[] arr2 = new char[arrA.length * 2 - 1];for (int i = 0; i < arrA.length * 2 - 1; i++) {if (i % 2 == 0) {arr2[i] = nnn[i / 2];} else {arr2[i] = ddd[ddd.length - i / 2 - 1];}}StringBuffer str = new StringBuffer();for (char s : arr2) {str.append(s);}String s = str.toString().replace("零佰零拾", "零").replace("零佰", "零").replace("零拾", "零");String noTailNumber;if (n == 0) {noTailNumber = "";} else if (n % 100 == 0 && n >= 100) {noTailNumber = s.substring(0, s.length() - 2);} else if (n % 10 == 0 && n % 100 != 0 && n >= 10) {noTailNumber = s.substring(0, s.length() - 1);} else {noTailNumber = s;}return noTailNumber;}

  这段代码中的

.replace(“零佰零拾”, “零”).replace(“零佰”, “零”).replace(“零拾”, “零”)

  这一部分,本来是在此方法之后的取零步骤进行操作的,可是遇到了一些问题(末尾有零,其他位数后转换效果不好等情况),结果现在去不掉了,所以依旧留着.

  拼接完成之后就是拼接"万"类的前后字符串:

private static String nameWanChinese(int n) {String sN = String.valueOf(n);char[] arrN = sN.toCharArray();char[] arrStart = new char[arrN.length - 4];char[] arrEnd = new char[4];System.arraycopy(arrN, 0, arrStart, 0, arrN.length - 4);System.arraycopy(arrN, arrN.length - 4, arrEnd, 0, 4);StringBuffer strStart = new StringBuffer();for (char s : arrStart) {strStart.append(s);}String start = strStart.toString();StringBuffer strEnd = new StringBuffer();for (char s : arrEnd) {strEnd.append(s);}String end = strEnd.toString();if ((Integer.parseInt(end) < 1000 && Integer.parseInt(end) > 0) || (Integer.parseInt(start) % 10 == 0 && Integer.parseInt(start) >= 10&&Integer.parseInt(end)!=0)|| (Integer.parseInt(start) % 100 == 0 && Integer.parseInt(start) >= 100&&Integer.parseInt(end)!=0)|| (Integer.parseInt(start) % 1000 == 0 && Integer.parseInt(start) >= 1000&&Integer.parseInt(end)!=0)) {return (nameChinese(Integer.parseInt(start)) + "萬零" + nameChinese(Integer.parseInt(end)));} else {return (nameChinese(Integer.parseInt(start)) + "萬" + nameChinese(Integer.parseInt(end)));}}

  这里面最长的那一串是if ((Integer.parseInt(end) < 1000 && Integer.parseInt(end) > 0) || (Integer.parseInt(start) % 10 == 0 && Integer.parseInt(start) >= 10&&Integer.parseInt(end)!=0)|| (Integer.parseInt(start) % 100 == 0 && Integer.parseInt(start) >= 100&&Integer.parseInt(end)!=0)|| (Integer.parseInt(start) % 1000 == 0 && Integer.parseInt(start) >= 1000&&Integer.parseInt(end)!=0)),这段代码是为了让100,000,101,000,这类的数字准确输出读法,否则会出现"十万零"或者"十万一千"这样的错误读法.

  接着,再创建方法来对不同的数据进行不同的方法调用:

    private static String getZeroName(String s) {String numberFinal;if (Integer.parseInt(s) <= 9999 && Integer.parseInt(s) >= 0) {numberFinal = nameChinese(Integer.parseInt(s));} else if (Integer.parseInt(s) <= 99999999 && Integer.parseInt(s) >= 10000) {numberFinal = nameWanChinese(Integer.parseInt(s));} else/* if (Integer.parseInt(s) <= 2147483647 && Integer.parseInt(s) >= 100000000) {numberFinal = nameYiChinese(Integer.parseInt(s));} else */ {numberFinal = "数据溢出";}return numberFinal;}

  注释掉的代码原本是为了输出亿元部分,但是经过多次尝试,未能创造出合适的方法,不甘心,不舍得删除,所以依旧留着------------------------------

  最后,对所得到的数据进行最后一次过滤:

    private static String getFinalChineseName(String s) {String zeroName = getZeroName(s);String finalName = zeroName.replace("零萬", "萬").replace("零拾零萬", "萬").replace("零佰零拾", "零").replace("零佰", "零").replace("零拾", "零").replace("零萬", "萬").replace("零億", "億");return finalName;}

  其实这步骤在思考过程中反而是最先想出来的,只不过这一步才进行了最彻底地实现.
  最后就是主方法进行调用,并添加计数器进行统计

public static void main(String[] args) {//char[] num = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};//char[] digit = {'拾', '佰', '仟'};//char[] digitHuge = {'萬', '億'};Scanner sc = new Scanner(System.in);System.out.println("请输入一个数字");String get = sc.next();String OK = getFinalChineseName(get);System.out.println(OK);//为了输出读法,方便进行验证int count = 0;for (int i = 1; i <= Integer.parseInt(get); i++) {count += getFinalChineseName(String.valueOf(i)).length();}System.out.println(count);}

完整代码

public class ReadAnyNumber {public static void main(String[] args) {long start = System.currentTimeMillis();//char[] num = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};//char[] digit = {'拾', '佰', '仟'};//char[] digitHuge = {'萬', '億'};Scanner sc = new Scanner(System.in);System.out.println("请输入一个数字");String get = sc.next();String OK = getFinalChineseName(get);System.out.println(OK);int count = 0;for (int i = 1; i <= Integer.parseInt(get); i++) {count += getFinalChineseName(String.valueOf(i)).length();}long end = System.currentTimeMillis();System.out.println(count);System.out.println("从一读到一亿需要读" + (count + 2) + "个汉字,共耗时" + (end - start) + "毫秒");}private static String getFinalChineseName(String s) {String zeroName = getZeroName(s);String finalName = zeroName.replace("零萬", "萬").replace("零拾零萬", "萬").replace("零佰零拾", "零").replace("零佰", "零").replace("零拾", "零").replace("零萬", "萬").replace("零億", "億");return finalName;}private static String getZeroName(String s) {String numberFinal;if (Integer.parseInt(s) <= 9999 && Integer.parseInt(s) >= 0) {numberFinal = nameChinese(Integer.parseInt(s));} else if (Integer.parseInt(s) <= 99999999 && Integer.parseInt(s) >= 10000) {numberFinal = nameWanChinese(Integer.parseInt(s));} else/* if (Integer.parseInt(s) <= 2147483647 && Integer.parseInt(s) >= 100000000) {numberFinal = nameYiChinese(Integer.parseInt(s));} else */ {numberFinal = "数据溢出";}return numberFinal;}private static String nameWanChinese(int n) {String sN = String.valueOf(n);char[] arrN = sN.toCharArray();char[] arrStart = new char[arrN.length - 4];char[] arrEnd = new char[4];System.arraycopy(arrN, 0, arrStart, 0, arrN.length - 4);System.arraycopy(arrN, arrN.length - 4, arrEnd, 0, 4);StringBuffer strStart = new StringBuffer();for (char s : arrStart) {strStart.append(s);}String start = strStart.toString();StringBuffer strEnd = new StringBuffer();for (char s : arrEnd) {strEnd.append(s);}String end = strEnd.toString();if ((Integer.parseInt(end) < 1000 && Integer.parseInt(end) > 0) || (Integer.parseInt(start) % 10 == 0 && Integer.parseInt(start) >= 10&&Integer.parseInt(end)!=0)|| (Integer.parseInt(start) % 100 == 0 && Integer.parseInt(start) >= 100&&Integer.parseInt(end)!=0)|| (Integer.parseInt(start) % 1000 == 0 && Integer.parseInt(start) >= 1000&&Integer.parseInt(end)!=0)) {return (nameChinese(Integer.parseInt(start)) + "萬零" + nameChinese(Integer.parseInt(end)));} else {return (nameChinese(Integer.parseInt(start)) + "萬" + nameChinese(Integer.parseInt(end)));}}private static String nameChinese(int n) {String bigNumber = getBigNumber(n);char[] nnn = bigNumber.toCharArray();String digit = getDigit(n);char[] ddd = digit.toCharArray();String sA = String.valueOf(n);char[] arrA = sA.toCharArray();char[] arr2 = new char[arrA.length * 2 - 1];for (int i = 0; i < arrA.length * 2 - 1; i++) {if (i % 2 == 0) {//if(n%10 != 0)arr2[i] = nnn[i / 2];} else {arr2[i] = ddd[ddd.length - i / 2 - 1];}}StringBuffer str = new StringBuffer();for (char s : arr2) {str.append(s);}String s = str.toString().replace("零佰零拾", "零").replace("零佰", "零").replace("零拾", "零");String noTailNumber;if (n == 0) {noTailNumber = "";} else if (n % 100 == 0 && n >= 100) {noTailNumber = s.substring(0, s.length() - 2);} else if (n % 10 == 0 && n % 100 != 0 && n >= 10) {noTailNumber = s.substring(0, s.length() - 1);} else {noTailNumber = s;}return noTailNumber;}private static String getBigNumber(int numberR) {int number = numberR;char[] num = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};String sNumber = String.valueOf(number);char[] arr = sNumber.toCharArray();char[] arr2 = new char[arr.length];for (int i = 0; i < arr.length; i++) {arr2[i] = num[Integer.parseInt(String.valueOf(arr[i]))];}StringBuffer str = new StringBuffer();for (char s : arr2) {str.append(s);}String numberBig = str.toString();return numberBig;}private static String getDigit(int numberR) {int number = numberR;char[] digit = {'拾', '佰', '仟'};String sNumber = String.valueOf(number);char[] arr = sNumber.toCharArray();char[] arr2 = new char[arr.length - 1];for (int i = 0; i < arr.length - 1; i++) {arr2[i] = digit[i];}StringBuffer str = new StringBuffer();for (char s : arr2) {str.append(s);}String digitDo = str.toString();return digitDo;}
}

  最后结果别忘记加2,因为还有个"一亿"没统计,哈哈
  顺便加入时间,看看我的笨方法需要耗时多久…………

//输出结果
请输入一个数字
99999999
玖仟玖佰玖拾玖萬玖仟玖佰玖拾玖
1412990003
从一读到一亿需要读1412990003个汉字,共耗时222302毫秒

缺点

  显而易见,太坑了,居然耗时这么久!!
  而且此方法也没有对亿进行分析!!

请教

  希望各位大神对我这个方法提提意见,或者有更好的方法,让我学习学习

从一读到一亿需要读多少个汉字?相关推荐

  1. 产品经理要读什么书?怎么读?

    产品相关知识可以在:http://www.aipingce.com/进行学习,本文转自:http://www.aipingce.com/article-22960-1.html 首先,我个人还是非常推 ...

  2. oracle 优化逻辑读过高,详述逻辑读与arraysize的关系

    我们都知道,数据块是oracle最基本的读写单位,但用户所需要的数据,并不是整个块,而是块中的行,或列.当用户发出SQL语句时,此语句被解析执行完毕,就开始了数据的抓取阶段,在此阶段,服务器进程会先将 ...

  3. mysql 快照读 幻读,InnoDB的MVCC如何解决不可重复读和快照读的幻读,当前读用next-key解决幻读...

    InnoDB默认的隔离级别是RR(可重复读),可以解决脏读和不可重复读,只解决了快照读情况下的幻读问题,当前读情况下解决幻读问题得靠next-key锁. mysql如何实现避免幻读: 在快照读读情况下 ...

  4. 开机预读快还是不预读快_WIN 7下的超级预读比VISTA要好,改进不少!推荐开启超级预读!...

    预读技术是微软vista和windows7默认开启的程序,原意是增加程序运行和开机速度,但事与愿违,该技术已经变成与UAC几乎一样的垃圾,普通用户建议关闭,原因有: 1.程序本身额外增加系统负担,启用 ...

  5. kubernetes英语怎么读_英语音标怎么读?如何从零基础英语音标入门英语口语学习...

    英语是学习英语的基础,学好音标才能够提高英语发音的准确性,为后面更复杂的口语练习打下坚实的地基,同时也对词汇的记忆有着很大的影响. 英语趣配音特别整理汇总了48个音标及发音技巧供大家参考学习 音标 单 ...

  6. mysql实战20 | 幻读是什么,幻读有什么问题?

    在上一篇文章最后,我给你留了一个关于加锁规则的问题.今天,我们就从这个问题说起吧. 为了便于说明问题,这一篇文章,我们就先使用一个小一点儿的表.建表和初始化语句如下(为了便于本期的例子说明,我把上篇文 ...

  7. 中国地质大学英语语音学习笔记(四):英语连读——弱读、冠词连读方法(包括元音字母前添加an的原因)和词间辅音加元音的连读方法

    前言   本笔记整理于中国地质大学(武汉)的一门英语发音课程:英语语音,的第九,十单元的文档资料.包括冠词连读(不定冠词连读,定冠词连读,元音字母前用an的原因),弱读和辅音加元音连读的发音技巧.整理 ...

  8. 茜在人名可以读xi吗_茜读xi还是qian?

    01 茜可以读xi,也可以读qian,通常用于外国女子名字译音时多读xī,而qiàn多用于中国名.茜,本义是草名即"茜草"读音为qiàn时,指茜草,在古汉语中也指"深红& ...

  9. mysql 幻读 mvcc_MVCC 能解决幻读吗?

    MySQL通过MVCC(解决读写并发问题)和间隙锁(解决写写并发问题)来解决幻读 MySQL InnoDB事务的隔离级别有四级,默认是"可重复读"(REPEATABLE READ) ...

最新文章

  1. c语言 真假条件跳转语句,什么是无条件跳转语句(C++)
  2. Python十大装腔语法
  3. 两帧点云刚性配准的ICP算法
  4. 华御密盾智能防信息泄密系统
  5. python微信推送消息_Python编程之微信推送模板消息功能示例
  6. raid0 raid1 raid5 raid10工作模式的工作原理及特点
  7. NamingException
  8. [NOI2009]管道取珠
  9. 如何解决“企业内控”存在的形式化问题
  10. ImageView和ImageButton的区别
  11. android studio javah命令,Android Studio 配置 javah 和 ndk-build 快捷编译
  12. HTML---鼠标悬停导航栏变颜色
  13. 中国大陆芯片设计企业名单
  14. 企业微信每日定时自动上报
  15. 格式化 命令 linux,linux格式化命令(linux格式化磁盘命令fdisk详解)
  16. idea 去掉author波浪线
  17. 计算机英语句子及译文,英语经典句子
  18. 欲登千层楼,又何惧寒风
  19. nn.Linear()函数详解
  20. IDEA 配置Go环境,编写Golang代码,学习笔记(一)

热门文章

  1. C#OOP之四 深入理解方法
  2. 数据会说谎的真实例子有哪些
  3. 长短期记忆网络(Long Short-Term Memory,LSTM)及其变体双向LSTM和GRU
  4. JMeter最简单汉化中文版
  5. 全方位掌握Apache Spark 2.0七步走(二)
  6. 听说你在写Python爬虫,你对浏览器的开发者工具了解多少?【多图预警】
  7. Asterix and Obelix
  8. C#下的一个好用的日历库(sxtwl_cpp),支持农历转公历,和公历转农历等功能
  9. 网页登陆安全身份认证(I KEY1000)
  10. 常用的新媒体工具有哪些?