`
rappy
  • 浏览: 42689 次
  • 性别: Icon_minigender_1
  • 来自: 天涯海角
文章分类
社区版块
存档分类
最新评论

闲来消遣之一:任给一个自然数,统计从0开始数到这个数时1的出现次数.

阅读更多
   项目终于告一段落了!很好,在元旦前准时提交客户.
   不过,30号,我们还是忙到了31号凌晨.感觉经理挺负责任的.虽然大家为了赶项目,忙了一周,都身心俱累,但我们还是坚持下来了,没有任何怨言,只有解决问题后的那份欢愉.
   可以安心回家过个假期了.
   元旦放假回家闲得慌(汗,我就是劳苦命,闲不住!),刚好本本带回家,就开起来,练练手.
   想起先前在某个群里有人说起一个题目,感觉挺有意思的.由于先前项目赶,一直没有多余的心思想其它的,渐渐的忘了.正好现在想起来,真好!
  
   题目:任给一个自然数,包括0,统计从0开始数到这个数,1的出现次数.
   这个题目的解法有n多.相信很多人看了,可以列出一大摞的解决方法出来.
   我这边就说下我的思路.
   我打算按个,十,百位...这样来统计.
   比如给个数2000.
   那在千位上有1的数是1000-1999,总共1000个.
   在百位上有1的数是100-199,1100-1199,总共200个.
   在十位上有1的数是10-19,110-119,...,1910-1919总共200个.
   在个位上有1的数是1,11,21,...,1991,总共200个.
   这样一来就可以统计出一个规律了.
   对于数m--常量, n(1,10,100,...)位上1的个数k(n)=m/(10*n)*n
   这里假设m都是可以被n整除的
    要做到上面的条件,可以对m进行拆分(分治策略)
   比如2345就可以拆成2000+300+40+5,这样每个拆分的数都可以用上面的函数来统计,最后结果加起来就是了.
   代码如下(JAVA实现).
 /**
	 * 计算从1数到n的过程中1的出现次数.
	 * 
	 * @param n
	 * @return
	 */
	public long getNumbersOfOne(long n) {
		long amount = 0;
		int t = 0;
		int i = 1;
		int x = 0;
		for (; (t = new Double(n / Math.pow(10, i)).intValue()) > 0; i++) {
			// 除数
			x = new Double(Math.pow(10, i - 1)).intValue();
			amount += t * x;
			// 余数
			amount = countRemind(n, amount, i, x);
		}
		x = new Double(Math.pow(10, i - 1)).intValue();
		// 余数
		amount = countRemind(n, amount, i, x);

		return amount;
	}

	/**
	 * 计算余数中该位上1的出现次数.
	 * 
	 * @param n
	 * @param amount
	 * @param i
	 * @param x
	 * @return
	 */
	private long countRemind(long n, long amount, int i, int x) {
		int k = new Double(n % Math.pow(10, i)).intValue();
		int m = BASE * x - 1;
		if (m == 0) {
			// 个位的
			if (k >= 1)
				amount += 1;
		} else {
			int num = k - m;
			if (num >= x)
				amount += x;
			else if (num >= 0)
				amount += num;
		}
		return amount;
	}

该算法复杂度是logN级别的.
不知道大家有什么更好的解法,欢迎贴上来!
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics