计数介于0和N Ks的数量数量、Ks

2023-09-11 22:37:25 作者:莪本輕狂

我已经看到了这样的问题:

I have seen questions like:

count介于0和N 0的个数? count介于0和N 1的个数? 数介于0和N 2S多少? ...

这些题型非常相似,要求找到总数的KS(即K = 0,1,2,...,9)显示号码范围 [0,N]

These kinds of questions are very similar of asking to find the total number that Ks (i.e. K=0,1,2,...,9) are shown in number range [0, N].

例如:

输入: K = 2,N = 35 输出: 14 详细信息: 2 列表之间 [0,35] 2, 12,20,21,22,23,24,25,26,27,28,29,32 ,而不是 22 将被计作为两次(如 22 包含两个 2 S) Input: K=2, N=35 Output: 14 Detail: list of 2s between [0,35]: 2, 12, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, not that 22 will be counted as twice (as 22 contains two 2s)

有每个人(如果您寻找它可用)的解决方案。通常情况下, O(日志N)需要时间通过递归取最高位​​考虑,等来解决这些问题。 //tianrunhe.word$p$pss.com/2012/06/04/count-the:计数介于0和N 2秒的数量的一个实例可以用下面的过程(从这里):

There are solutions for each of them (available if you search for it). Usually, O(log N) time is needed to solve such questions by recursively taking the highest digit into consideration, and so on. One example of counting the number of 2s between 0 and N can be solved by the following procedure (borrowed from here):

// Take n = 319 as example => 162
int numberOf2sBetween0AndN(int n) 
{
    if (n < 2)
        return 0;

    int result = 0;
    int power10 = 1;
    while (power10 * 10 < n)
        power10 *= 10;

    // power10 = 100
    int msb = n / power10; // 3
    int reminder = n % power10; // 19

    /*** Count # of 2s from MSB ***/
    if (msb > 2)    // This counts the first 2 from 200 to 299
        result += power10;
    if (msb == 2)   // If n = 219, this counts the first 2 from 200 to 219 (20 of 2s).
        result += reminder + 1;

    /*** Count # of 2s from reminder ***/
    // This (recursively) counts for # of 2s from 1 to 100; msb = 3, so we need to multiply by that.
    result += msb * numberOf2s(power10);
    // This (recursively) counts for # of 2s from 1 to reminder
    result += numberOf2s(reminder);

    return result;
}

问:

需要注意的是,我们不能简单地改变所有 2 S部在上述code到 1 取值为了解决计数 0 N 。看来,我们必须处理不同的(不平凡),用于不同的情况。

Question:

Note that, we cannot simply change all 2s part in the above code to 1s in order to solve the problem of counting the number of 1s between 0 and N. It seems that we have to handle differently (not trivial) for different cases.

有没有我们可以按照处理所有 K S(即 K = 0,1,2的一般步骤,...,9 ),即类似如下的功能?的

Is there a general procedure we can follow to handle all Ks (i.e. K=0,1,2,...,9), i.e. something like the following function?

int numberOfKsBetween0AndN(int k, int n) 

测试用例:

下面是一些测试情况下,如果你想查询你的解决方案:

Test cases:

关于在EXCEL里面第一个数,减去下面n个数,最后得到一个数值,用什么公式呀

Here are some test cases if you want to check your solution:

K = 1,N = 1 1 K = 1,N = 5 1 K = 1,N = 10 2 K = 1,N = 55 16 K = 1,N = 99 20 K = 1,N = 10000 :4001 K = 1,N = 21345 :18821 K = 2,N = 10 1 K = 2,N = 100 20 K = 2,N = 1000 300 K = 2,N = 2000 601 K = 2,N = 2145 781 K = 2,N = 3000 :1900 k=1, N=1: 1 k=1, N=5: 1 k=1, N=10: 2 k=1, N=55: 16 k=1, N=99: 20 k=1, N=10000: 4001 k=1, N=21345: 18821 k=2, N=10: 1 k=2, N=100: 20 k=2, N=1000: 300 k=2, N=2000: 601 k=2, N=2145: 781 k=2, N=3000: 1900

推荐答案

我相信这是什么是你需要的,简单的,一般的和快速的。

I believe this is what's your need, simple, general and fast.

下面是在Python的例子:

Below is an example in Python:

的检查很简单,使用字符串找到所有号码从'0'串 - N,和计数的比赛时间氏/ code>,它是缓慢的,但我们可以用它来检查其他的解决方案。

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   

快速和通用的解决方案

K≠0

对于每k = [1,9],它更清楚,在[0,9]我们可以发现1比赛在第一位;

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;

在[0,99]我们可以发现在第一位1场比赛,并在第二位的10场比赛,因此所有为1 * 10 ^ 1 + 10 * 10 ^ 0 = 20场比赛,

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,

在[0999]我们可以发现在第一位1场比赛,排在第二位的10场比赛和第三位的100场比赛,因此所有为1 * 10 ^ 2 + 10 * 10 ^ 1 + 100 * 10 ^ 0 = 300匹配...

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...

因此​​,我们可以很容易得出结论,在[0,10 ^ L - 1],有 1×10 ^(L-1)匹配

So we can easily conclude that in [0,10^l - 1], there is l * 10^(l-1) matches.

更一般地,我们可以找到。[0,F * 10 ^ L - 1],有 F * 10 ^(L-1)* L 匹配

More general, we can find in [0,f * 10^l - 1], there f*10^(l-1) * l matches.

因此​​,这里的解决方案:

So here is the solution:

例如,N ='ABCD',K ='K'

for example, n = 'abcd', k = 'k'

第一步:如果n = 0或n ='',返回0;算上A000的比赛,使用上式中,L = LEN(N) step2A:如果== K,我们知道所有的BCD匹配,所以加 BCD 匹配。 step2B:如果a> K,我们知道所有的数k ***是匹配的,所以加 10 ^(L-1)匹配 第三步:先切一点,并设定N ='BCD',转到步骤1 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

下面是code对于k≠0:

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是有点棘手,因为 0 *** 等于 *** 和将不允许算呢游行'0'。

k = 0

k = 0 is a bit of tricky, because 0*** is equal to *** and will not allowed to count it marches '0'.

所以对于k≠0的解决方案不能满足K = 0,但这个想法是相似的。

So solution for k ≠ 0 can't fit k = 0. But the idea is similar.

我们可以发现,如果n&LT; 100,必须有 N / 10 + 1 相匹配。

We can find that if n < 100, there must be n/10 + 1 matches.

如果n个[100199],它更类似的是当k≠0在[0,99],有20场比赛;

if n in [100,199], it's much similar that as k ≠ 0 in [0,99], has 20 matches;

如果n个[100999],它更类似的是当k≠0 [100999],有20 * 9场比赛;

if n in [100,999], it's much similar that as k ≠ 0 in [100,999], has 20 * 9 matches;

如果n在[1000,9999],它更类似的是当k≠0在[1000,9999],拥有300 * 9匹配...

if n in [1000,9999], it's much similar that as k ≠ 0 in [1000,9999], has 300 * 9 matches...

更一般的,如果n [10 ^ L,K * 10 ^ L-1],它将具有 1×10 ^(L-1)* K 匹配。

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:

例如,N ='ABCD',K ='0',递归步取值 = 0

for example, n = 'abcd', k = '0', recurse step s = 0

step0:当n ='',返回0;如果n&LT; 100,返回 N / 10 + 1 ; step1A:N ='F(......)中,f是n的第一位。若S> 0,假设我们已经处理了第一位之前,所以0可以把当k≠0,所以若f == 0,所有的休息(...)应该匹配,只需添加(...)+ 1的比赛 step1B:若S> 0且f> 0,L = LEN(N),我们知道会有 10 **(L-1)匹配的第一位的 0(...),和(L-1)* 10 **(L-2)(...) 第二步:如果s == 0,算上火柴'F(...) - 1,使用上的公式 第三步:若S> 0时,只检查(...)为s == 0的第二步,将获得(F-1)* 10 **(1-2)*( L-1),(F-1),因为我们不能起动形式 0 *** 。 第四步:切开的第一位女,并设定N ='(......),S + = 1,转到步骤1 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

下面是k的code = 0:

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 ))

测试

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!"

测试所有的k [0,9]从N [0,10000],它通过了所有的情况。

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.