剑指 Offer 43. 1~n整数中1出现的次数

1~n整数中1出现的次数

问题来源

https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/
在这里插入图片描述

暴力法

对于暴力的方法,只需要从1开始,对1 -> n 中的所有数进行枚举,然后依次判断该数的每一位(个位,十位,百位 .... ....)是否为1

  • 如果该位是1,计数器 ans++
  • 如果该位不是1,继续判断下一位
	int countDigitOne(int n) {
        int ans = 0;
        
        for(int i = 1; i <= n; i++)
        {
            int num = i;
            while(num)
            {
                if(num % 10 == 1)
                    ans++;
                num /= 10;
            }
        }

        return ans;
    }

当数据量特别大的时候,最后的结果是会超时的
在这里插入图片描述

优化后的写法

既然暴力的方法不可以,那么我们是否可以根据当前位(个位,十位,百位 .... ....)的数字,然后确定出以该位为中心,一共有多少个1的情况。

对于这种做法,我们可以把一个数字(n n-1 … … 1)分成三部分,设当前位为第 x 位:

  • 高位,n - > x + 1 位,也就是 n n-1 … … x + 1
  • 当前位,第 x 位,也就是 x
  • 低位,x-1 x-2 … … 1,也就是 x - 1 x - 2 1

在这里插入图片描述
对于当前位的数值,有这么几种情况

  1. 当前位的数值为 0 ,也就是 x = 0

在这里插入图片描述

  1. 当前位的数值为1,也就是 x = 1

  2. 当前位的数值大于1,也就是 x > 1

在这里插入图片描述

    int countDigitOne(int n) {
        int ans = 0;
        long i = 1; //i表示哪一位的数字,i = 1表示个位,i = 10 表示十位

        while(n / i != 0)
        {
            //当前位的高位数字
            long high = n / (10 * i);
            //当前位的数字
            long cur = (n / i) % 10;
            //当前位的低位数字
            long low = n - (n / i) * i;

            if(cur == 0)
                ans += high * i;
            else if(cur == 1)
                ans += high * i + low + 1;
            else
                ans += (high + 1) * i;

            i *= 10;
        }
        return ans;
    }

算法的时间复杂度为O(log n),也就是 n 有多少位,就循环多少次

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章