233. Number of Digit One 详细解答

Approach #1 Brute force [Time Limit Exceeded]

Intuition

Do as directed in question.

Algorithm

  • Iterate over ii from 11 to nn:
  • Convert ii to string and count \text{'1'}’1’ in each integer string
  • Add count of \text{'1'}’1’ in each string to the sum, say countrcountr

C++

int countDigitOne(int n)
{
    int countr = 0;
    for (int i = 1; i <= n; i++) {
        string str = to_string(i);
        countr += count(str.begin(), str.end(), '1');
    }
    return countr;
}

Complexity Analysis

  • Time complexity: O(n*log_{10}(n))O(nlog10(n)).
  • We iterate from 11 to nn
  • In each iteration, we convert integer to string and count '1' in string which takes linear time in number of digits in ii, which is log_{10}(n)log10(n).

  • Space complexity: O(log_{10}(n))O(log10(n)) Extra space for the countr and the converted string \text{str}str.


Approach #2 Solve it mathematically [Accepted]

Intuition

In Approach #1, we manually calculated the number of all the '1'1s in the digits, but this is very slow. Hence, we need a way to find a pattern in the way '1'1s (or for that matter any digit) appears in the numbers. We could then use the pattern to formulate the answer.

Consider the 11s in \text{ones}ones place , \text{tens}tens place, \text{hundreds}hundreds place and so on... An analysis has been performed in the following figure.

Number of digit one

From the figure, we can see that from digit '1' at \text{ones}ones place repeat in group of 1 after interval of 1010. Similarly, '1' at \text{tens}tens place repeat in group of 10 after interval of 100100. This can be formulated as (n/(i*10))*i(n/(i10))i.

Also, notice that if the digit at \text{tens}tens place is \text{'1'}’1’, then the number of terms with \text{'1's}’1’s is increased by x+1x+1, if the number is say \text{"ab1x"}"ab1x". As if digits at \text{tens}tensplace is greater than 11, then all the 1010 occurances of numbers with '1'1 at \text{tens}tens place have taken place, hence, we add 1010. This is formluated as {\min(\max((\text{n mod (i*10)} )-i+1,0),i)}min(max((n mod (i*10))i+1,0),i).

Lets take an example, say n= 1234n=1234.

No of \text{'1'}’1’ in \text{ones}ones place = 1234/101234/10(corresponding to 1,11,21,...1221) + \min(4,1)min(4,1)(corresponding to 1231) =124124

No of \text{'1'}’1’ in \text{tens}tens place = (1234/100)*10(1234/100)10(corresponding to 10,11,12,...,110,111,...1919) +\min(21,10)min(21,10)(corresponding to 1210,1211,...1219)=130130

No of \text{'1'}’1’ in \text{hundreds}hundreds place = (1234/1000)*100(1234/1000)100(corresponding to 100,101,12,...,199) +\min(135,100)min(135,100)(corresponding to 1100,1101...1199)=200200

No of \text{'1'}’1’ in \text{thousands}thousands place = (1234/10000)*10000(1234/10000)10000 +\min(235,1000)min(235,1000)(corresponding to 1000,1001,...1234)=235235

Therefore, Total = 124+130+200+235 = 689124+130+200+235=689.

Herein, one formula has been devised, but many other formulae can be devised for faster implementations, but the essence and complexity remains the same. The users are encouraged to try to divise their own version of solution using the mathematical concepts.

Algorithm

  • Iterate over ii from 11 to nn incrementing by 1010 each time:
  • Add (n/(i*10))*i(n/(i10))i to \text{countr}countr representing the repetition of groups of $$i$ sizes after each (i*10)(i10) interval.
  • Add {\min(\max((\text{n mod (i*10)} )-i+1,0),i)}min(max((n mod (i*10))i+1,0),i) to \text{countr}countr representing the additional digits dependant on the digit in iith place as described in intuition.

C++

int countDigitOne(int n)
{
    int countr = 0;
    for (long long i = 1; i <= n; i *= 10) {
        long long divider = i * 10;
        countr += (n / divider) * i + min(max(n % divider - i + 1, 0LL), i);
    }
    return countr;
}

Complexity analysis

  • Time complexity: O(log_{10}(n))O(log10(n)).
  • No of iterations equal to the number of digits in n which is log_{10}(n)log10(n)

  • Space complexity: O(1)O(1) space required.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值