I believe this is what's your need, simple, general and fast.
Below is an example in Python:
Slow Checker
The checker is simple, use string
to find all number in string from '0' - 'n', and count the match times of k
, it's slow but we can use it to check other solutions.
import string
def knChecker( k, n ):
ct = 0
k = str(k)
for i in xrange(0,n+1):
ct += string.count(str(i),k)
return ct
Fast and General Solution
k ≠ 0
for every k = [1,9],it's much clear that in [0,9] we can find 1 match in first bit;
in [0,99] we can find 1 matches in first bit and 10 matches in second bit, so all is 1*10^1 + 10*10^0 = 20 matches,
in [0,999] we can find 1 matches in first bit ,10 matches in second bit and 100 matches in third bit, so all is 1*10^2 + 10*10^1 + 100*10^0 = 300 matches...
So we can easily conclude that in [0,10^l - 1], there is l * 10^(l-1)
matches.
More general, we can find in [0,f * 10^l - 1], there f*10^(l-1) * l
matches.
So here is the solution:
for example, n = 'abcd', k = 'k'
- step1: if n = 0 or n = '', return 0; count matches in 'a000', use the up formula, l = len(n)
- step2A: if a == k, we know all 'bcd' is matched, so add
bcd
matches.
- step2B: if a > k, we know all 'k***' is matched, so add
10^(l-1)
matches.
- step3: cut the first bit a, and set n = 'bcd', go to step1
Here is the code for k ≠ 0:
def knSolver( k, n ):
if k == '0':
return knSolver0( n, 0 )
if not n:
return 0
ct = 0
n = int(n)
k = int(k)
l = len(str(n))
f = int(str(n)[:1])
if l > 1:
ct += f * 10 ** (l-2) * (l-1)
if f > k:
ct += 10 ** (l-1)
elif f == k:
ct += n - f * 10 ** (l-1) + 1
return ct + knSolver( k, str(n)[1:])
k = 0
k = 0 is a bit of tricky, because 0***
is equal to ***
and will not allowed to count it marches '0'.
So solution for k ≠ 0 can't fit k = 0. But the idea is similar.
We can find that if n < 100, there must be n/10 + 1
matches.
if n in [100,199], it's much similar that as k ≠ 0 in [0,99], has 20 matches;
if n in [100,999], it's much similar that as k ≠ 0 in [100,999], has 20 * 9 matches;
if n in [1000,9999], it's much similar that as k ≠ 0 in [1000,9999], has 300 * 9 matches...
More general, if n in [10^l,k*10^l-1], it will has l*10^(l-1)*k
matches.
So here is the solution:
for example, n = 'abcd', k = '0', recurse step s
= 0
- step0: if n = '', return 0; if n < 100, return
n/10+1
;
- step1A: n='f(...)', f is first bit of n. if s > 0, say we have handled the first bit before, so 0 can treat as k ≠ 0, so if f == 0, all rest (...) should match, just add (...)+1 matches.
- step1B: if s > 0 and f > 0, l = len(n), we know there will be
10 ** (l-1)
matched in the first bit of 0(...)
, and (l-1) * 10 ** (l-2) in (...)
- step2: if s == 0, count matches in 'f(...)-1', use the up formula
- step3: if s > 0, just check for (...) as s == 0 in step2, will get
(f-1) * 10 ** (l-2) * (l-1)
, (f-1), because we can't start form 0***
.
- step4: cut the first bit f, and set n = '(...)', s += 1, go to step1
Here is the code of k = 0:
def knSolver0( n, s ):
if n == '':
return 0
ct = 0
sn = str(n)
l = len(sn)
f = int(sn[:1])
n = int(n)
if n < 100 and s == 0:
return n / 10 + 1
if s > 0 and f > 0:
ct += 10 ** (l-1) + (l-1) * 10 ** (l-2)
elif s > 0 and f == 0:
ct += n + 1
if n >= 100 and s == 0:
ct += 10
for i in xrange(2,l):
if i == l-1:
ct += i * 10 ** (i-1) * (f-1)
else:
ct += i * 10 ** (i-1) * 9
elif s > 0 and f != 0:
ct += (f-1) * 10 ** (l-2) * (l-1)
return int(ct + knSolver0( sn[1:], s+1 ))
Test
print "begin check..."
for k in xrange(0,10):
sk = str(k)
for i in xrange(0,10000):
#knSolver( sk, i )
if knChecker( sk, i ) != knSolver( sk, i ):
print i, knChecker( sk, i ) , knSolver( sk, i )
print "check end!"
Test all k[0,9] from n[0,10000], it passed all cases.
The test will take a bit long time, because of the checker is slow. If remove the checker, all cases in my laptop take about one second.