Log4X

链路纵横
在www.blogjava.net上看到的有趣题目

http://www.blogjava.net/Jack2007/archive/2008/10/16/234742.html

原文作者是Jack.Wang

题目描述:

给定一个十进制数N,写下从1开始,到N的所有整数,然后数一下其中出现的所有"1"的个数。
 例如:
 N=2,写下1,2。这样只出现了1个"1"
 N=12,写下 1,2,3,4,5,6,7,8,9,10,11,12。这样"1"的个数是5
 请写出一个函数,返回1到N之间出现"1"的个数,比如 f(12)=5

 

一开始看这个就想到遍历1-N,每个数里面的1数量加起来,这样算法复杂度为 N乘N的位数,即O(NLogN)。后来看了原作所写,这个问题有复杂度为o(LogN)的解,于是思考了一番,用递归实现了。

同时写上O(NLogN)的遍历算法和原文作者的算法以作比较 

 

  1 package puzzles;
  2 
  3 interface Algrithm {
  4     public int resolve(int number);
  5 }
  6 
  7 class RecursiveAlgrithm implements Algrithm {// 按位递归算法,o(LogN)
  8     @Override
  9     public int resolve(int number) {
 10         if (number == 0) {
 11             return 0;
 12         }
 13         int length = (int) Math.log10(number);
 14         if (length == 0) {
 15             return 1;
 16         } else {
 17             int currentLvl = scale(10, length);
 18             int head = number / currentLvl;
 19             if (head > 1) {
 20                 return currentLvl + (head) * resolve(currentLvl - 1)
 21                         + resolve(number - head * currentLvl);
 22             } else {
 23                 return number - currentLvl + 1 + (head)
 24                         * resolve(currentLvl - 1)
 25                         + resolve(number - currentLvl);
 26             }
 27         }
 28     }
 29 
 30     public int scale(int a, int b) { //指数运算
 31         int res = 1;
 32         for (int i = 0; i < b; i++) {
 33             res = a * res;
 34         }
 35         return res;
 36     }
 37 }
 38 
 39 class EnumerateAlgrithm implements Algrithm {// 遍历算法,o(NLogN)
 40 
 41     @Override
 42     public int resolve(int number) {
 43         int sum = 0;
 44         for (int i = 0; i <= number; i++) {
 45             sum += findInSingleNum(i);
 46         }
 47         return sum;
 48     }
 49 
 50     private int findInSingleNum(int number) {//单个数中包含'1'数量
 51         int res = 0;
 52         while (number > 0) {
 53             if (number % 10 == 1) {
 54                 res++;
 55             }
 56             number = number / 10;
 57         }
 58         return res;
 59     }
 60 }
 61 
 62 class ReferedAlgrithm implements Algrithm {//原作者的算法,o(LogN)
 63     @Override
 64     public int resolve(int n) {
 65         int count = 0;
 66         int factor = 1;
 67         int lower;
 68         int current;
 69         int higher;
 70         while (n / factor != 0) {
 71             lower = n - (n / factor) * factor;
 72             current = (n / factor) % 10;
 73             higher = n / (factor * 10);
 74             switch (current) {
 75             case 0:
 76                 count += higher * factor;
 77                 break;
 78             case 1:
 79                 count += higher * factor + lower + 1;
 80                 break;
 81             default:
 82                 count += (higher + 1* factor;
 83             }
 84             factor *= 10;
 85         }
 86         return count;
 87 
 88     }
 89 }
 90 
 91 public class MsPuzzle {
 92 
 93     public static void calculateWith(Algrithm al) {
 94         long start = System.nanoTime();
 95         int res = al.resolve(100000000);
 96         long end = System.nanoTime();
 97         System.out.println(al.getClass().getName()+":"+res);
 98         System.out.println("time cost:" + (end - start) + "ns");
 99     }
100 
101     public static void main(String[] arg) {
102         MsPuzzle.calculateWith(new RecursiveAlgrithm());
103         MsPuzzle.calculateWith(new ReferedAlgrithm());
104         MsPuzzle.calculateWith(new EnumerateAlgrithm());
105     }
106 }
107 

 

 

由于ReferedAlgrithm和RecursiveAlgrithm的算法太快,以至于以毫秒计时都是0ms,因此改用纳秒

output:

puzzles.RecursiveAlgrithm:80000001
time cost:96940ns
puzzles.ReferedAlgrithm:80000001
time cost:4191ns
puzzles.EnumerateAlgrithm:80000001
time cost:25053647670ns

可以看到原作者的算法是最快的,递归算法虽然算法复杂度同为o(LogN),不过递归在性能上不如循环,因此也差了一个数量级

而最后o(NLogN)复杂度的算法,性能则整整差了6个数量级以上...

这个差距,大概抵得上20年的硬件性能的发展了吧.

各位有兴趣也可以用C#分别实现下这几种算法,看看和java耗时相比如何^^

posted on 2008-10-17 00:56  YYX  阅读(1604)  评论(13编辑  收藏  举报