Algorithm 小于给定数字且无重复数字的数字的数目

Algorithm 小于给定数字且无重复数字的数字的数目,algorithm,math,combinations,digits,Algorithm,Math,Combinations,Digits,我们如何找到小于给定数字且没有重复数字的数字数 例如,小于100的此类数字为90。(11,22,33,44,55,66,77,88,99有重复数字,因此不包括重复数字) 同样地,对于小于1000的数字,必须排除101、110、122、202等数字。这里有一种方法可以加快速度。请注意,max number中的位数与解决方案(我将称之为非的位数)之间存在相关性 十亿后,你必须重复一个数字。你可以考虑两种情况: 短于限制的数字 与某个数字的限制不同的数字 d-位数的计数为9*9*8*…=9*9!/

我们如何找到小于给定数字且没有重复数字的数字数

例如,小于100的此类数字为90。(11,22,33,44,55,66,77,88,99有重复数字,因此不包括重复数字)


同样地,对于小于1000的数字,必须排除101、110、122、202等数字。

这里有一种方法可以加快速度。请注意,max number中的位数与解决方案(我将称之为
的位数)之间存在相关性


<>十亿后,你必须重复一个数字

。你可以考虑两种情况:

  • 短于限制的数字
  • 与某个数字的限制不同的数字
d
-位数的计数为
9*9*8*…=9*9!/(9-d)(第一位数字不能为零)。小于
d
的所有数字的计数是0位数+的计数。。
d-1
-位数的计数。这些总和可以预先计算(甚至硬编码)

带有
f
首个数字的
d
数字的计数为
(10-f)*…*(10-(d-1))=(10-f)/(10-d)。您还可以预编译阶乘

伪代码:

To precompute fac:
  - fac = int[10];
  - fac[0] = 1;
  - for i in 1..10:
    - fac[i] = fac[i-1] * i;

To precompute count_shorter:
  - cs = int[10];
  - cs[0] = 0;
  - cs[1] = 1; // if zero is allowed
  - for i in 1..10:
    - cs[i+1] = cs[i] + 9 * fac[9] / fac[10-i]
  - count_shorter = cs;

To determine the count of numbers smaller than d:
  - sl = strlen(d)
  - if sl > 10
    - return count_shorter[11]
  - else
    - sum = 0
    account for shorter numbers:
    - sum += count_shorter[sl]
    account for same-length numbers; len=count of digits shared with the limit:
    - sum += 9* fac[9] / fac[10-sl];
    - for every len in 1..{sl-1}:
      count the unused digits less than d[len]; credits to @MvG for noting:
      - first_opts = d[len]-1;
      - for every i in 0..{len-1}:
        - if d[i] < d[len]
          - first_opts -= 1;
      - sum += first_opts * fac[9-len] / fac[10-sl] 
  - return sum
预计算fac:
-fac=int[10];
-fac[0]=1;
-对于1..10中的i:
-fac[i]=fac[i-1]*i;
要预计算计数,请执行以下操作:
-cs=int[10];
-cs[0]=0;
-cs[1]=1;//如果允许为零
-对于1..10中的i:
-cs[i+1]=cs[i]+9*fac[9]/fac[10-i]
-计数=cs;
要确定小于d的数字的计数,请执行以下操作:
-sl=斯特伦(d)
-如果sl>10
-返回计数较短[11]
-否则
-总和=0
较短的数字:
-总和+=计数较短[sl]
说明相同长度的数字;len=与限制共享的位数:
-总和+=9*fac[9]/fac[10 sl];
-对于1..{sl-1}中的每个len:
计算小于d[len]的未使用数字;@MvG因注意到以下事项而获得的积分:
-第一个选项=d[len]-1;
-对于0..{len-1}中的每个i:
-如果d[i]
以下是一些实现此功能的代码。代码中的注释。基本思想是每次迭代最后一个数字的位数,对于每个数字位置,可以计算在该位置之前具有相同位数但在当前位置具有较小位数的数字。这些函数是相互构建的,因此最末端的
cntsigner
函数就是您实际调用的函数,也是注释最详细的函数。我已经检查过,对于30000个参数,这与蛮力实现是一致的。我已经与其他实现进行了广泛的比较,所以我相当确信这段代码是正确的

从数学导入阶乘
def吸入口(n,r):
“”“计数从n个元素集中选择r个元素的方法,而不使用
重复项,考虑到顺序“”
返回阶乘(n)/阶乘(n-r)
def forLength(长度,numDigits,numFirst):
“”“计数形成长度为非重复数字的数字的方法
从一组numDigits可能的数字中获取数字,
第一个数字的可能选项为numFirst。”“”
返回numFirst*take(numDigits-1,长度-1)
def未处理(数字,i):
“”“给定一个数字字符串,递归计算
不大于输入且不重复的数字
数字。递归从i=0开始。”“”
如果i==len(位数):
返回真值
而数字[i]中的数字[:i]或未被处理(数字,i+1):
数字[i]=1
对于范围内的j(i+1,len(位数)):
数字[j]=9
如果数字[i]<0:
数字[i]=9
返回错误
返回真值
def最后计数(n):
“”“计算最后一个小于n的数字
没有重复的数字
数字=[int(i)表示str(n-1)中的i]
未重新处理时(数字,0):
数字=[9]*(长度(数字)-1)
而数字[0]==0:
数字=数字[1:]
断言len(数字)==len(设置(数字))
返回数字
def CNT更小(n):
如果n<2:
返回0
位数=上次计数(n)
cnt=1#保证对lastCounted中的一个进行计数
l=长度(位数)
对于范围(1,l)内的i:
#用更少的数字计算所有数字
#第一位数字非零,其余所有数字
cnt+=forLength(i,10,9)
firstDigits=设置(范围(10))
对于枚举中的i,d(位数):
#计数等于最后计数到位置的数字
#但在位置i有一个较小的数字
firstHere=firstDigits&set(范围(d))#较小但不重复
如果i==0:#这是第一个数字
firstHere.discard(0)#不能以零开头
cnt+=长度(l-i,10-i,len(第一个在这里))
第一位数字。放弃(d)
返回cnt

编辑:
cntsigner(9876543211)
返回8877690,这是可以使用非重复数字形成的最大数字数。事实上,这是超过10=3628800让我困惑了一段时间,但这是正确的:当你认为你的序列填充到长度10,那么序号的序号是允许的,除了数字中的某个零点之外。这将使计数增加到纯排列的计数之上。

您是在尝试计数这些数字还是枚举它们?您可以添加一些上下文吗?数字的最大大小是多少?速度要求是什么?为什么不简单地迭代和计数呢?数字的最大大小是10^18。迭代将非常缓慢。最大值仅为10^10,因为不需要大于9876543210的值。你可以负担得起。没有代表数字的数字数量是有限的,所以我们可以建立一个查找表来得到O(1):pCo中的结果
To precompute fac:
  - fac = int[10];
  - fac[0] = 1;
  - for i in 1..10:
    - fac[i] = fac[i-1] * i;

To precompute count_shorter:
  - cs = int[10];
  - cs[0] = 0;
  - cs[1] = 1; // if zero is allowed
  - for i in 1..10:
    - cs[i+1] = cs[i] + 9 * fac[9] / fac[10-i]
  - count_shorter = cs;

To determine the count of numbers smaller than d:
  - sl = strlen(d)
  - if sl > 10
    - return count_shorter[11]
  - else
    - sum = 0
    account for shorter numbers:
    - sum += count_shorter[sl]
    account for same-length numbers; len=count of digits shared with the limit:
    - sum += 9* fac[9] / fac[10-sl];
    - for every len in 1..{sl-1}:
      count the unused digits less than d[len]; credits to @MvG for noting:
      - first_opts = d[len]-1;
      - for every i in 0..{len-1}:
        - if d[i] < d[len]
          - first_opts -= 1;
      - sum += first_opts * fac[9-len] / fac[10-sl] 
  - return sum