Reputation: 312
Problem Statement:
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.
Efficient Solution:
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;
}
My question:
I found the solution to the question in one of the forums, I am finding it hard to comprehend the solution. I understand its a very simple one but please help me by explaining in detail.
Thank you
Upvotes: 7
Views: 7870
Reputation: 557
Try to observe the pattern here
Consider N = 2196, which has 4 digits having place values ones, tens, hundreds and thousands.
Now, try to observe the pattern:
Numbers having 1 at ones position
1 11 21 31 41 51 ...
Numbers having 1 at tens position
10 110 210 310 ...
11 111 211 311 ...
......................
19 119 219 319 ...
Numbers having 1 at hundreds position
100 1100 2100 ...
101 1101 2101 ...
102 1102 2102 ...
....................
199 1199 2199 ...
Can you see a cluster of 1 number with a time period of 10 in ones,
a cluster of 10 numbers with a time period of 100 in tens and a cluster of 100 numbers with a time period of 1000 in hundreds?
So, our final answer would be Summation of (N / Time Period) * Cluster Size
But, be careful with the last case,
if N % Time Period != 0
, There is one more cluster which will not be complete.
Try to figure that out by taking N = 2196.
From the above analysis:
Here is the C++ code
int solve(int A){
int ans = 0;
for(int i = 1; i <= A; i *= 10){
// i is cluster size.
// temp is time period.
int temp = i * 10;
// min(max(A%temp-i+1, 0), i) -> this part is going to take care
// of extra last cluster.
ans += ((A/temp) * i) + min(max(A%temp-i+1, 0), i);
}
return ans;
}
Upvotes: 5
Reputation: 23955
So, in the code you included in your question, digit
is moving through the digits from right to left and q
corresponds with how many x
s, an increasing power of ten, are in the number. Each cycle in the while loop counts how many ones are in that position. Let's look at an example:
n => 131
digit => 1, 3, 1
q => 13, 1, 0
x => 1, 10,100
q * x => 13*1
// there are 13 ones in the 10^0 position from 0 to 130 (13 counts of 10)
digit == 1 => n % 1 + 1 = 0 + 1 = 1
// there is 1 one in the 10^0 position from 131 to 131
(the remainder for the counts of 10)
---
q * x => 1*10
// there are 10 ones in the 10^1 position from 0 to 100 (1 count of 100): 10 to 19
digit == 3 => x = 10
// there are 10 ones in the 10^1 position from 101 to 131: 110 to 119
(the remainder for the counts of 100)
---
q * x => 0*100
// there are 0 ones in the 10^2 position from 0 to 0 (0 counts of 1000)
digit == 1 => n % 100 + 1 = 31 + 1
// there are 32 ones in the 10^2 position from 0 to 131
(the remainder for the counts of 1000)
Upvotes: 4
Reputation: 5243
Here is one way to approach this: Suppose that n < 10^k
, i.e. n
can be represented by k
decimal digits. Let's try to construct all positive numbers that have k
or less decimal digits, with 1
s in them.
There are 2^k
possibilities to place 1
s in some of the k
bits.
For each choice of 1
placements, we can easily count all positive numbers that have maximum of k
digits, and are smaller than n
.
For example, all numbers that match the pattern yxxx1xx11x
, where each x
can be 0
or 2-9
, and y
is 2-9
. Notice the special y
there, because if y==0
, the x
after it is not allowed to be zero. There are 8 * 9^6
possibilities. So this pattern contributes 3 * 8 * 9^6
to the total count, because each such number contains 3 1
's.
This gets a little bit complicated, because we need to restrict the number to those that are smaller or equal to n
. This means that not every combination of y
and x
s are valid. For instance, if n=6239914230
, then y<=6
, and for y<6
, the first x
must be at most 2, etc...
Upvotes: 0