leetcode 233. Number of Digit One

Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.

For example:
Given n = 13,
Return 6, because digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.

这道题具有一定的思维难度。用暴力法的话不可取,会TLE。暴力法就是从1遍历到n,算每个数字中1的个数,相加,时间复杂度是 O ( n l o g ( n ) ),太高了,不符合要求。

因此,应该使用算术方法来解决该问题。

Intuition

我们尝试着找到数字 1 出现的模式。考虑 1 出现在个位、十位、百位......上的情况,得到如下图的分析。


从图中,我们可以看到,个位上的数字 1 每隔 10 个数出现一次,十位上的数字 1 每隔 100 个数出现一次......这个可以用公式 (n/(i*10))*i 来表达。

除此之外,如果 n 在十位上的数字是 1 ,即"ab1x"那么增加的数字个数为 x+1。如果 n 在十位上的数字大于 1 ,那么所有在十位上为 1 的10个数字都会出现,那么可以增加  10这个可以用公式 min(  max( (n mod (i*10))-i+1, 0) , i  来表示。

if n = xyzdabc

如果我们考虑千位上 1 的出现次数,应该是:

(1) xyz * 1000                     if d == 0
(2) xyz * 1000 + abc + 1           if d == 1
(3) xyz * 1000 + 1000              if d > 1

因此我们可以从最低位到最高位来遍历 n 中的所有数字,得到结果

public int countDigitOne(int n) {

    if (n <= 0) return 0;
    int q = n, x = 1, ans = 0;
    do {
        int digit = q % 10;
        q /= 10;
        ans += q * x;
        if (digit == 1) ans += n % x + 1;
        if (digit >  1) ans += x;
        x *= 10;
    } while (q > 0);
    return ans;

}

举个例子,如果 n= 1234

 ’1’ 在个位上的出现次数 = 1234/10 (如 1,11,21,...1221) + (加上 1231)  =124

’1’ 在十位上的出现次数 = (1234/100)*10 (如 10,11,12,...,110,111,...1919) + 10 (加上 1210,1211,...1219) =130

 ’1’ 在百位上的出现次数 = (1234/1000)10(如 100,101,12,...,199) + 100 (加上 1100,1101...1199) =200 

 ’1’ 在千位上的出现次数 = (1234/10000)*10000 + 23(加上 1000,1001,...1234)=235

所以总共 = 124+130+200+235 = 689

Complexity analysis

  • Time complexity: O(log(n)).
  • No of iterations equal to the number of digits in n which is log(n)

  • Space complexity: O(1) space required.


猜你喜欢

转载自blog.csdn.net/huanghanqian/article/details/79698361
今日推荐