编程之美 2.4 -----求1的数目

题目是这样的:给定一个正整数N,从1到N一共出现过多少个1?

如N=12,则f(12)=5,因为1,2,3,4,5,6,7,8,9,10,11,12共出现5次“1”。

书上的思路很巧妙,考虑到一个数字的每一位中1出现的次数,如果该位为0,则该位出现1的数目只与其前面的数字有关,如果为1,则与前面后面数字都有关,如大于1,仍只与前面数字有关。Java代码如下:

public void Book(){
    int n = num;
    int iCount = 0;
    int iFactor = 1;
    int iLowerNum = 0;
    int iCurrentNum = 0;
    int iHigherNum = 0;
   
    while(n/iFactor != 0){
    iLowerNum = n - (n / iFactor) * iFactor;
    iCurrentNum = n / iFactor % 10;
    iHigherNum = n / (iFactor * 10);
   
    switch(iCurrentNum){
    case 0:
    iCount += iHigherNum * iFactor;
    break;
    case 1:
    iCount += iHigherNum * iFactor + iLowerNum + 1;
    break;
default:
    iCount += (iHigherNum + 1) * iFactor;
    break;
    }
    iFactor *= 10;
    }
    System.out.println("The biaozhun anwser is " + iCount);
    }


自己的算法:

分别考虑不同位数的数字中1出现的个数。这种方法没有书上给出的简单,但是结果是正确的。

具体是这样的:

书中有公式:f(10^n - 1) = n * 10^(n - 1);即n位数中最多有1的个数是n*10^(n - 1),如3位数最大为999,从1至999共有 3 * 10 ^2 = 300个。

先给出一个N位数x,可以先利用上面公式求出(N - 1)位及以下所有数字中包含1的个数,剩下只需求解所有小于等于x的N位数中包含1的个数。

如x = 23435,先利用公式求出所有4位数中(1至9999)包含1的个数 ,为 4000个。然后求解10000到23435中1的个数。在求解N位数中包含1的个数时

需要注意某位前面的数字是有限制的,因为它是从最小的N位数10000(N个0)开始的。

具体代码如下:

    public void MyCal2(){
        int length = 0, tmp = num;
        //求出该数字的位数
        while(tmp > 0){
            length++;
            tmp /= 10;
        }
        System.out.println("length = " + length);
        //求出所有len - 1到1位的所有包含1的结果
        int sum = cal(length - 1);
        
        int pow = (int)Math.pow(10, length - 1);
        System.out.println("The init result is " + sum + ", the length = " + 
        ", the pow = " + pow);
        int current = num / pow;
        int pre = 0;
        int pos = num - current * pow;
        int left = (current == 1) ? (pos + 1): pow;
        
        for(int idx = length - 1; idx >= 1; idx--){
        //pow /= 10;
        pre = num / pow;
            current = (num - pre * pow )/(pow / 10);    
            pos = num % pow  - current * (pow / 10);
            
            System.out.println("In the calculation2, the pre is " + 
            pre + "  current = " + current + ", pos = " + pos
            + ", pow = " + pow );
            
            pre -= (int)Math.pow(10, length - idx -1);
            pre += 1;
            
            System.out.println("After translation, the pre is " + 
            pre );
            if(current > 1){
            left += pre * (int)Math.pow(10, idx - 1);
            } else if(current == 1){
            left += (pre - 1) * (int)Math.pow(10, idx - 1) + pos + 1;
            }else if(current == 0){
            left += (pre - 1) * (int)Math.pow(10, idx - 1);
            }
               pow /= 10;
        }
        System.out.println("In the calculation2, the result is " + (sum + left));
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值