几个一

一. 题目

     给定一个十进制的正整数,写下从1开始,到N的所有整数,然后数一下其中出现“1”的个数。

     要求: 写一个函数 f(N) ,返回1 到 N 之间出现的 “1”的个数。例如 f(12) = 5。

              在32位整数范围内,满足条件的“f(N) =N”的最大的N是多少。

二. 设计思想

     对于一个正整数,比如22133。依次计算个位、十位、百位、千位。。,然后相加。计算的过程是:个位3出现1的次数是1。十位3中1出现的次数受前面位数和后面位数影响,

他出现1个次数为(十位数字3+1)*个位数字1出现次数+(十位前面的数字221+1)*1.接下来就是依次类推。因为正整数的位数不是已知,所以我采用了WHILE循环。在循环中重点考虑的是这个数字是不是1,分两类考虑。别的就没什么了,正常敲代码就可以

三. 源代码

   

import java.util.Scanner;


public class onetime {

    /**
     * @param args
     */
    static int sunmer(int n){
        int sum=0;
        int factor=1;
        int n2=n;
        int remainder=0;
        while(n2>0)
        {
            int num=(n2+9)/10;
            int true_num; 
            if(n2%10==1)
            {
                true_num=(num-1)*factor+remainder+1;
            }
            else
            {
                true_num=num*factor;
            }
            sum+=true_num;
            n2/=10;
            factor*=10;
            remainder=n%factor;
        }
        return sum;
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.print("请输入一个正整数: ");
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int sum=sunmer(n);
        
        System.out.println("从一到该整数中‘1’出现的次数为:");
        System.out.println(sum);
        System.out.println("在32位整数范围内,满足条件的'f(N) =N'的最大的N是:");
        for(int i=2147483647;i>0;i--)
        {
            int sum1;
            sum1=sunmer(i);
            if(sum1==i){
                System.out.println(i);
                break;
            }
        }
        
    }

}

四. 运行结果

    

五.总结

    刚开始我的想法不是这样的,把一个数6537,看成6000/500/30/7。几个阶段进行计算。关于这种算法重复的问题,我是这么想的,先从1算到6000,这是第一个阶段。其次是500。其实求得是6001--6500之间出现的“1”的个数,因为千位上没有1,所以省略。接下来依次类推。但是没有考虑到的问题是如果是1560.这就需要另外考虑了,如果每一位都要考虑1。代码将变得臃肿,远远不如上述的办法简单。所以最终我采用了这个办法。通过这次编程,我认识到你自己所认为最简单的方法不一定是最简单的。

原文地址:https://www.cnblogs.com/zchenjian/p/4552846.html