Algorithm 求给定范围内具有给定位数的整数数的算法

Algorithm 求给定范围内具有给定位数的整数数的算法,algorithm,Algorithm,如果我得到了列表形式的完整数字集list,我想知道它们在给定范围[a,B]内可以形成多少个(有效)整数,我可以使用什么算法来有效地实现这一点 例如,给定一个数字列表(包含重复项和零)list={5,3,3,2,0,0},我想知道在[a,B]=[20400]范围内可以形成多少个整数。例如,在这种情况下,20、23、25、30、32、33、35、50、52、53、200、203、205、230、233、235、250、253、300、302、303、305、320、323、325、330、332、3

如果我得到了列表形式的完整数字集
list
,我想知道它们在给定范围
[a,B]
内可以形成多少个(有效)整数,我可以使用什么算法来有效地实现这一点

例如,给定一个数字列表(包含重复项和零)
list={5,3,3,2,0,0}
,我想知道在
[a,B]=[20400]
范围内可以形成多少个整数。例如,在这种情况下,
20、23、25、30、32、33、35、50、52、53、200、203、205、230、233、235、250、253、300、302、303、305、320、323、325、330、332、335、350、352、353
都是有效的

Step 1: Find the number of digits your answers are likely to fall in. In your 
        example it is 2 or 3.

Step 2: For a given number size (number of digits)

    Step 2a: Pick the possibilities for the first (most significant digit). 
    Find the min and max number starting with that digit (ascend or descending
    order of rest of the digits). If both of them fall into the range:
        step 2ai: Count the number of digits starting with that first digit and
        update that count
    Step 2b: Else if both max and min are out of range, ignore. 
    Step 2c: Otherwise, add each possible digit as second most significant digit
    and repeat the same step 
通过案例解决:

对于2的数字大小,即

0_ : Ignore since it starts with 0
2_ : Minimum=20, Max=25. Both are in range. So update count by 3 (second digit might be 0,3,5)
3_ : Minimum=30, Max=35. Both are in range. So update count by 4 (second digit might be 0,2,3,5)
5_ : Minimum=50, Max=53. Both are in range. So update count by 3 (second digit might be 0,2,3)
3号:

0__ : Ignore since it starts with 0
2__ : Minimum=200, max=253. Both are in range. Find the number of ways you can choose 2 numbers from a set of {0,0,3,3,5}, and update the count.
3__ : Minimum=300, max=353. Both are in range. Find the number of ways you can choose 2 numbers from a set of {0,0,2,3,5}, and update the count.
5__ : Minimum=500, max=532. Both are out of range. Ignore.
更有趣的情况是,最大限值为522(而不是400):


如果范围很小,但列表很大,那么简单的解决方案就是在范围内循环,并检查是否可以从列表中生成每个数字。通过使用一个哈希表或一个带有计数的数组,可以快速检查列表中的每个数字仍然可以使用的次数

对于n个数字的列表,z为零,下限为l,上限为u

步骤1:简单的东西

考虑一种情况,即您有一个2位数的下限和一个4位数的上限。虽然确定有多少2位和4位数字在边界内可能很棘手,但我们至少知道所有3位数字都在边界内。如果边界是2位数和5位数,你知道所有3位数和4位数都是公平的

让我们把它推广到一个下界,一个下界是a位,一个上界是b位。对于a和b之间的每个k(不包括a和b本身),所有k位数字都在该范围内

有多少这样的数字?考虑如何选择它们:第一个数字必须是n个非零的数字(其中一个(N-Z)数字),其余的是从尚未被挑选的列表中挑选出来的,即(N-1)第二个数字的选择,(N-2)为第三,等等,所以这看起来像阶乘,但是有一个奇怪的第一个术语。选取了n中的多少个数字?为什么,它们中的k,这意味着我们必须除以(n-k)!为了确保我们总共只选取k位数字。所以每个k的方程看起来像:(n-z)(n-1)/(n-k)!!插入(a,b)范围内的每一个k,就有(a+1)到(b-1)位数,所有这些数字都必须有效

步骤2:边缘案例

当你考虑一个数字和B数字时,事情有点复杂。我不认为您可以通过所有可能的数字组合避免启动深度优先搜索,但如果超过边界,您至少可以中止整个分支

例如,如果您的列表包含{7,5,2,3,0},且上界为520,则您的搜索可能会如下所示:

Pick the 7: does 7 work in the hundreds place? No, because 700 > 520;
  abort this branch entirely (i.e. don't consider 752, 753, 750, 725, etc.)
Pick the 5: does 5 work in the hundreds place? Yes, because 500 <= 520.
    Pick the 7: does 7 work in the tens place? No, because 570 > 520.
      Abort this branch (i.e. don't consider 573, 570, etc.)
    Pick the 2: does 2 work in the tens place? Yes, because 520 <= 520.
        Pick the 7: does 7 work in the ones place? No, because 527 > 520.
        Pick the 3: does 3 work in the ones place? No, because 523 > 520.
        Pick the 0: does 0 work in the ones place? Yes, because 520 <= 520.
        Oh hey, we found a number. Make sure to count it. 
    Pick the 3: does 3 work in the tens place? No; abort this branch.
    Pick the 0: does 0 work in the tens place? Yes.
        ...and so on. 
选择7:7在几百个地方有效吗?不,因为700>520;
完全中止此分支(即不考虑752, 753, 750、725等)。
选择5:5在几百个地方有效吗?是的,因为500 520。
中止这个分支(即不考虑573, 570,等等)
选择2:2在十位中起作用吗?是的,因为520。
选择3:3在1的位置起作用吗?不,因为523>520。

选择0:0是否在1位置工作?是的,因为520@NiklasB.:不,这不是家庭作业。好的,只是想确定:)我只是在数字列表中添加了一个
5
,以便理解你的步骤1。看起来相当复杂。运行时间是多少?@littleEinstein它并不复杂,因为您可以使用递归实现。复杂性大约是n*k,其中n是可能的候选数的不同,k是需要考虑的整数大小。如果您的范围是10^6到10^20,这是非常有效的。它有点低效(但比线性搜索更好,如果你的搜索范围看起来像[123456,213456]你能像你说的那样用递归编写一个工作代码吗?谢谢!@littleEinstein我会写代码,但我会假设1,01和001是不同的可能性。否则代码就太复杂了。
def calculateMinMax( currentVal, digSize, remSet):
    numRemain = digSize - len(currentVal)
    minPosVal = int( sorted(remSet)[:numRemain] )
    maxPosVal = int( sorted(remSet,reverse=True)[:numRemain] )
    return minPosVal,maxPosVal

numberPermutations(remSet,digSize, currentVal): Basically number of ways 
you can choose (digSize-len(currentVal)) values from remSet. See permutations
with repeats.
Pick the 7: does 7 work in the hundreds place? No, because 700 > 520;
  abort this branch entirely (i.e. don't consider 752, 753, 750, 725, etc.)
Pick the 5: does 5 work in the hundreds place? Yes, because 500 <= 520.
    Pick the 7: does 7 work in the tens place? No, because 570 > 520.
      Abort this branch (i.e. don't consider 573, 570, etc.)
    Pick the 2: does 2 work in the tens place? Yes, because 520 <= 520.
        Pick the 7: does 7 work in the ones place? No, because 527 > 520.
        Pick the 3: does 3 work in the ones place? No, because 523 > 520.
        Pick the 0: does 0 work in the ones place? Yes, because 520 <= 520.
        Oh hey, we found a number. Make sure to count it. 
    Pick the 3: does 3 work in the tens place? No; abort this branch.
    Pick the 0: does 0 work in the tens place? Yes.
        ...and so on.