2.4 1的数目
2015-08-12 21:25
861 查看
1. 前言
本文的一些图片, 资料 截取自编程之美2. 问题描述
3. 问题分析
对于第一个问题 书中给出了两种算法第一种 : 遍历一次1-n 统计出每一个数的出现的1的次数, 然后累加起来
第二种 : 利用数学方法找出规律, 然后计算 [呵呵, 一看就知道经过仔细思考过的算法效率高的多]
现在以 113为例解释一下第二种算法
1-113 中1出现的次数 = 1-113中[个位为1的数字的个数 + 十位为1的数字的个数 + 百位为1的数字的个数]
所以 1-113 中1出现的次数为 : 12 + 14 + 14 = 40
个位为1 : [[0*100 + [0-9] * 10] + 1] / [1*100 + [0-1]*10 + 1] = 11 + 1
十位为1 : [0 * 100 + 1*10 + [0-9]] / [1*100 + 1*10 + [0-3]] = 10 + 4
百位为1 : [1*100 + 0*10 + [0-9]] + [1*100 + 1*10 + [0-3]] = 14
通过归纳法 我们可以得到如下结论 :
因为 1 - n 中1的个数 等于个位为1的数的个数 + 百位为1的数的个数 + … + 最高位为1的数的个数
令mask 为当前测试位数的权重, [high表示当前位之前的数字的值, low表示当前位之后的数字的值, [比如 : 123, 设当前位为第二位2, 那么high为1, low为3]]
则 以第2位为例 :
如果第二位为0 则1-n中1的个数为 high * mask
如果第二位为1 则1-n中1的个数为 high * mask + low + 1
如果第二位为2-9 则1-n中1的个数为(high + 1) * mask
对于第二个问题
书中给出的解法为, 求解f(n) == n的上界, 然后在从上界开始递减 寻找满足条件的数字, 对于这个思路, 我看了一下 也是一知半解
证明存在上界 :
求出上界 :
add at 2016.02.12
今天在伯乐在线上面又看见了一种比较巧妙的解法, 这里 我就直接上图了
附上帖子的location : http://group.jobbole.com/13802/
4. 代码
/** * file name : Test11FindNumOf1In1ToN.java * created at : 10:02:01 AM May 20, 2015 * created by 970655147 */ package com.hx.test03; public class Test11FindNumberOf1In1ToN { // 找到1到n 中所有的 1的个数[10进制表示] public static void main(String []args) { int n = 113; // 1602000 1604000 1606000 1608000 // findNumOf1In1ToN01(n); findNumOf1In1ToN02(n); // for(int i=0; i<999999999; i+=1000) { // int num = findNumOf1In1ToN02(i); // Log.log(i, (i > num) ); // if(i < num) { // Tools.awaitInput(); // } // } for(int i=0; i<100; i++) { int num = findNumOf1In1ToN02(i); // Log.log(i, (i > num) ); Log.log(Integer.toBinaryString(num)); Tools.awaitInput(); } } // 从1遍历到n 统计共出现了多少个1 public static int findNumOf1In1ToN01(int n) { int cnt = 0; for(int i=1; i<=n; i++) { cnt += numOf1InN(i); } Log.log(cnt); return cnt; } // 统计n中出现了多少个1 private static int numOf1InN(int n) { int cnt = 0; while(n > 0) { if(n % 10 == 1) { cnt ++; } n /= 10; } return cnt; } // 思路 : 1 - n 中1的个数 等于个位为1的数的个数 + 百位为1的数的个数 + ... + 最高位为1的数的个数 // mask 为当前测试位数的权重 // 以第2位为例 : 如果第二位为0 则1-n中1的个数为 high * mask // 如果第二位为1 则1-n中1的个数为 high * mask + low + 1 // 如果第二位为2-9 则1-n中1的个数为(high + 1) * mask // 2103为例 // 第二位为0 十位为1的数的个数为高位[百位, 千位][0 - 20][21个] * 低位[个位][0 - 9][10个] = 21 * 10 = 210 // 2113为例 // 第二位为1 十位为1的数的个数为 (高位[百位, 千位][0 - 20][21个] * 低位[个位][0 - 9][10个]) + (高位为21[1个] * 低位为[0-3][4个]) = 22 * 10 + 3 + 1 = 224 // 2123为例 // 第二位为2 十位为1的数的个数为高位[百位, 千位][0 - 21][22个] * 低位[个位][0 - 9][10个] = 22 * 10 = 220 public static int findNumOf1In1ToN02(int n) { int mask = 1, high = 0, low = 0, cur = 0; int cnt = 0; while(n >= mask) { high = n / (mask * 10); low = n % mask; cur = (n / mask) % 10; if(cur == 0) { cnt += high * mask; } else if(cur == 1) { cnt += high * mask; cnt += (low + 1); } else { cnt += (high + 1) * mask; } mask *= 10; } Log.log(cnt); return cnt; } }
5. 运行结果
6. 总结
这里再一次的证明了, 算法和数学的紧密联系, …注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统