• 1的数目


     给你一个十进制的正整数N,求1~N所有数中出现“1”的的数目。
    比如
    N=2: 1    2 ,1的个数的1.
    N=5: 1   2  3  4  5  ,1的个数是1。
    N=12:1  2   3  4  5  6  7 8   9  10  11  12 ,1的个数是5.
      希望你能写一个函数F(N),返回1-N之间出现1的个数,F(12)=5;

    如何求得?

    方法一:先求某个整数中有几个1,然后再遍历1~N,将所有“1”加起来。

    #include <stdio.h>
    
    /* 计算某个整数中1的个数 */
    int count(int n)
    {
    	int count = 0;
    	while(n != 0)
    	{
    		count += (n%10 == 1)?1:0;
    		n /= 10;
    	}
    	return count;
    }
    
    /* 从1到n的整数中1出现的次数 */
    int Count1InAInterger1(int n)
    {
    	int i= 0,countnum = 0;
    	for(i = 1;i <= n;i++)
    	{
    		countnum += count(i);
    	}
    	return countnum;
    }
    
    
    int main(void)
    {
    	int N;
    	printf("请输入1个整数:");
    	scanf("%d",&N);
    	printf("方法1:%d中1的个数为:%d
    ",N,Count1InAInterger1(N));
    	return 0;
    }

    执行结果:


    分析一下这个方法的时间复杂度,其中count函数的时间复杂度是0(log2n),而Count1InAInterger1整体时间复杂度为O(n*log2n)

    这个算法的效率是致命的,当我们将整数输入较大时,如400000000000,至少要等待几十秒。


    有没有更好的办法呢?当然有,没有的话我也不会记录本学习日志了。


    下面是参考http://blog.csdn.net/wxl3105/article/details/7650318

    /*总体思路:先求个位上出现的1的个数,再找十位再找百位。。
    先看个位找找规律:

    整数      1的个数        1的列举
     5              1                   1
     15            2                   1,11   
     25            3                   1,11,21
     35            4                   1,11,21,31
     ...
     325     33                  1,11,21,31,41,...,301,311,321
     结论:个位上的1的数目s= N / 10 + 1;


     再看十位,找找规律:

    整数   1的个数                        1的列举
     25        10         10,11,12,13,14,15,16,17,18,19
     35        10         10,11,12,13,14,15,16,17,18,19
     95        10         10,11,12,13,14,15,16,17,18,19
     125       20        10,11,12,13,14,15,16,17,18,19,110,111,112,...,118,119
     725       80       10-19,110-119,210-219,310-319,410-419,510-519,610-619,710-719
     3225     330     10-19,20-29,...510-519,610-619,...1010-1019,1110-1119,1210-1219,...,3110-3119,3210-3219
     结论:十位上的1的数目s = (N / 100 + 1) * 10;
     ....
     将个位上的1的数目看作
     (N / 10 + 1) * 1;
     (N / 100 + 1 ) * 10; 十位上的
     猜想百位上1的数目应该是:
     (N / 1000 + 1 ) * 100


     特殊情况,当最高位为1时,最高位上1的数目为其余各位所组成的数加1,如125百位上的1的个数就是25+1=26个
     */

    #include <stdio.h>
    
    /* 从1到n的整数中1出现的次数 */
    int Count1InAInterger2(int n)
    {
    	int i = 1,j = 10,count = 0;
    	int tmp = 0;
    	if (n == 0)
    		return 0;
    	else if(n > 0 && n < 9)	 // 0~9只有1符合
    		return 1;	
    	if(n>=20&&n<=99)		//如果是20~99之间要再加上10
    		count = 10;
    	while(n/j)
    	{
    		tmp = n / j;
    		count += (tmp + 1) * i;
    		if(tmp == 1)
    			count +=  n % j + 1;
    		i *= 10;
    		j *= 10;
    	}
    	return count;  
    }
    
    int main(void)
    {
    	int N;
    	printf("请输入1个整数:");
    	scanf("%d",&N);
    	printf("方法2:%d中1的个数为:%d
    ",N,Count1InAInterger2(N));
    	return 0;
    }

    执行结果:


    这个时候再输入400000000   瞬间结果就出来了。


  • 相关阅读:
    Web 日志分析过程
    nginx系列之九:lua服务
    Linux网络编程之IO模型
    从URL输入到页面展现到底发生什么
    CentOS 日常运维十大技能
    以MySQL为例,详解数据库索引原理(1)
    Elasticsearch的特点以及应用场景
    Ubuntu1804编译安装LNMP
    golang 高级
    Centos7 安装 Redis
  • 原文地址:https://www.cnblogs.com/riskyer/p/3357954.html
Copyright © 2020-2023  润新知