java 1到n 求1的个数_java算法计算1到N个数里面一到底有多少个

java算法计算1到N个数里面一到底有多少个,统计1出现的总次数。首先是我做的,从1到n,对每个数字都数一下里面有多少个1,累加起来得到最终的结果。好大一个循环啊,循环里面还要再套循环,感觉挺垃圾的一个程序:

// 第0个元素表示当前数字的长度,第1个元素表示个位,第2个表示十位……

int[] num = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

int n = 12345;

int count = 0;

for (int i = 1; i <= n; i++) {

// 统计当前数字的1的个数

for (int k = 1; k <= num[0]; k++) {

if (num[k] == 1)

count++;

}

// 数字增加并进位

for (int k = 1; k <= num[0] + 1; k++) {

if (++num[k] == 10) {

num[k] = 0;

} else {

break;

}

}

// 更新数字的长度

num[0] = num[num[0] + 1] > 0 ? num[0] + 1 : num[0];

}

System.out.println(count);

接下来高手出现了,通过字符串的处理来解决问题,思路非常新颖啊,代码很简短,看上去很美:

// 在1到N中求出num的个数

private static int count(int N, int num) {

if (N <= 0 || num < 0 || num > 9)

return 0;

StringBuffer sb = new StringBuffer();

for (int i = 1; i < N + 1; i++)

sb.append(String.valueOf(i));

int totalCount = sb.toString().length();

String temp = sb.toString().replaceAll(String.valueOf(num), “”);

return totalCount – temp.length();

}

对这个程序提出了一个小小的疑问,那就是字符串太长了,整数是4字节的,最大的整数有2147483647这么大,输入进去很有可能造成字符串长度不够啊,就算够了也十分耗费内存。我只是想到了这个问题,但是没想到如何解决,另一个高手解决了它:

int len = 0;

for(int i=1;i<=n;i++)

len += (i+”").replaceAll(“[^1]“, “”).length();

System.out.println(len);

以上各种方法都是对从1到n的每一个数进行解析,如果n很大,则循环次数那是相当多啊,效率比较低下。论坛里的各位朋友讨论的比较热烈,一致认为用数学归纳法总结出一套规律,然后根据规律来编程效率会大幅提高。受此影响,我又对问题进行了分析,还真让我找到了规律,HOHO~好开心啊,代码真的很漂亮,思路也清晰。先简单介绍一下算法,以21047这个数字为例:

首先最高位会出现多少次1呢? 10000~19999共10000个1

再看次高位是个1:1000~1999,11000~11999,21000~21047,共有2*1000+48个1

再看第三位是个0:100~199,1100~1199,……20100~20199,共有21*100个1

再看第四位是个4:10~19,110~119,210~219……21010~21019,共有210*10+10个1

最后一位是个7,共有2104*1+1个1

根据上述分析,总结第n位(从左向右数)出现1的规律如下:

第0~n-1位组成的数字乘以跨度(如上述例子,最高位跨度10000,次高位跨度1000,也是很有规律的),然后再根据当前位是大于1?等于1?小于1?来加上一个可变的数值。具体点就是,若当前位大于1,则加上跨度;若当前位等于1,则加上尾数;若当前位等于0,则加0;

代码如下:

private static int count1(int n) {

int count = 0;

String num = n+”";

int x = (int)Math.pow(10, num.length()-1);

for(int i=0; i

count += Integer.parseInt(“0″+num.substring(0, i))*x;

if(num.charAt(i)>’1′) {

count += x;

}else if(num.charAt(i)==’1′) {

count += Integer.parseInt(“0″+num.substring(i+1))+1;

}

x /= 10;

}

return count;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值