过滤A010784序列的最快方法

时间:2011-04-30 00:49:07

标签: python algorithm filter oeis

OEIS处的A010784序列是仅包含具有不同数字的数字的序列。这是一个有限的数量。

我一直在尝试做的是在这个序列中找到具有某些属性的几个数字 例如:6是幅度10的不同数量。这可以如下:

  • 6 x 1 = 6
  • 6 x 2 = 12
  • 6 x 3 = 18
  • 6 x 4 = 24
  • 6 x 5 = 30
  • 6 x 6 = 36
  • 6 x 7 = 42
  • 6 x 8 = 48
  • 6 x 9 = 54
  • 6 x 10 = 60
  • 6 x 11 = 66(两个六个;这些不是两个不同的数字。)

现在我正在尝试提供几个数量级的最高数字 假设从1到20的所有订单。

我目前正在做的是从最高可能的不同数字循环,即9,876,543,210和最高的唯一数字1,直到非常低的数字。
这种方法感觉非常效率低下。至少,对我而言。

我很确定我错过了一些关于因素应该能够让事情变得更快的事情。

def unique_num(num):
    # Check whether number is unique.
    return Boolean

def unique_num_magnitude(num):
    # Check of which magnitude the unique number is
    return Integer

# Dictionary with the current highest values
# for each magnitude.
values = {1: 987654321...}

# Set limits
upper_limit = 9876543210
lower_limit = 1

for numbers in range(upper_limit, lower_limit, -1):
    unique = unique_num(num) # Boolean
    if (unique):
        magnitude = unique_num_magnitude(num)
        if (values[magnitude] < num):
            values[magnitude] = num

4 个答案:

答案 0 :(得分:1)

这不仅仅是排列问题吗?对于给定幅度M,你做10cM吗?

例如,在2级,有多少种方法可以从0..9中选择2位数? (实际上,它应该是从1到9中的一个和从0到9中的一个,其中第二个数字与第一个数字不匹配。)

你当然不需要全部检查它们并检查它们。只需设置一个并选择一个,然后选择另一个。更好的是,只需从头开始创建它们。首先做一切以1(10,12,13,14等)开头的东西,然后是以2开头的所有东西等。

答案 1 :(得分:1)

你有两个问题:

1)迭代A010784序列。

使用itertools.permutations生成连续的可能数字。

2)计算数字的大小。

您可以使用以下代码段确定某个数字是否只有唯一数字:

def unique_num(x):
    return len(str(x)) == len(set(str(x))

答案 2 :(得分:1)

当然有更好的方法。你应该自下而上建立数字,即如果一个数字a1 ... ak(这些是k个数字)不是N的大小,那么数字在结果的前k个数字中出现两次,对于任何被乘数2..N然后也不是任何数字b1 ... bm a1 ... ak。这提供了一种明确更快的递归枚举过程,因为它可以减少指数量的搜索空间。细节留给OP作为练习。

更长的解释:

假设有一个程序

 magnitude(number_str)

计算以10-base表示的数字number_str的大小,以便如果number_str包含至少一个数字的两次出现,则过程返回0,如果number_str则为1每个数字都是不同的,但是将数字乘以2导致数字出现多次,等等。

此程序可以用另一个程序实施

 unique_digits(number_str)

如果number_str中的所有数字都是唯一的,则返回true,否则返回false。

现在magnitude可以实现为

 magnitude(number_str):
   n = str_to_int(number_str)
   k = n
   i = 0
   while (unique_digits(int_to_str(k))):
     k = k + n
     i = i + 1
   return i

现在,此magnitude程序可以更改为nocarry_magnitude,以便巧妙地更改检查:

 nocarry_magnitude(number_str, limit):
   l = length(number_str)
   assert (l > 0)
   n = str_to_int(number_str)
   k = n
   i = 0
   while (unique_digits(right_substring(int_to_str(k), l))):
     k = k + n
     i = i + 1
     if (i == limit):
       break
   return i

此过程仅在循环中产品的最右边数字(最低位数字)检查多次出现的数字,因为原始输入中有数字。需要一个limit参数来确保过程终止,否则过程可能会在无限循环中运行。显然,对于任何字符串s,它都拥有

 magnitude(s) <= nocarry_magnitude(s, M) for large M

例如,取数字19:

 19 * 1 = 19
 19 * 2 = 38
 19 * 3 = 57
 19 * 4 = 76
 19 * 5 = 95
 19 * 6 = 114 // magnitude("19") = 5
 19 * 7 = 133 // nocarry_magnitude("19", 100) = 6

我在上面的简短描述中写的是,如果

 nocarry_magnitude(s, x) == k     for x > k

然后对于通过后缀s获得的任何字符串(在下面的x + s表示),它认为

 x : string of digits
 magnitude(x + s) <= nocarry_magnitude(x + s, m) <= nocarry_magnitude(s, m)
 when m >= magnitude(x + s)

第一个不平等来自上面的主张,第二个不平等来自nocarry_magnitude的定义。注意,幅度(x + s)<=幅度(s)通常是非定理,如

所示。
 magnitude( "56")  = 1  // 56 * 2 = 112
 magnitude("256")  = 12 // the first duplicate occurs at 3328

这是由携带引起的。 nocarry_magnitude忽略了一个进位,这就是为什么一个字符串的后缀总是与它的任何扩展一样大的nocarry-magnitude(向左,即高阶数字)。

现在你可以编写一个明显更快的递归程序,因为它可以搜索幅度至少为M的数字:

 search(str):
   if (str != ""):
     int n = nocarry_magnitude(str, M)
     if (n < M):
       return      # the optimization
     int k = magnitude(str)
     if (k >= M):
       store_answer(str)
   for d in ['1', '2', '3', '4', '5', '6', '7', '8', '9',
             '10', '20', '30', '40', '50', '60', '70', '80', '90']:
     search(d + str)

 search("")

这是一个完整的Python实现(搜索36级):

def unique_digits(s):
    r = (len(list(s)) == len(set(s)))
    return r

def magnitude(s):
    n = int(s)
    k = n
    assert n > 0
    i = 0
    while (unique_digits(str(k))):
        k = k + n
        i = i + 1
    return i

def nocarry_magnitude(s, limit):
    l = len(s)
    assert l > 0
    n = int(s)
    assert n > 0
    k = n
    i = 0
    while (unique_digits(str(k)[-l:])):
        k = k + n
        i = i + 1
        if (i >= limit):
            break
    return i

M = 36

def search(s):
    if (not(s == "")):
        n = nocarry_magnitude(s, M)
        if (n < M):
            return
        k = magnitude(s)
        if (k >= M):
            print "Answer: %s |" % s,
            i = int(s)
            k = i
            n = 1
            while (n <= M):
                print k,
                k = k + i
                n = n + 1
            print
    for d in ['1', '2', '3', '4', '5', '6', '7', '8', '9',
              '10', '20', '30', '40', '50', '60', '70', '80', '90']:
        search(d + s)

search("")

这是一个不到一秒的跑步;这找到答案'27',它似乎是提供记录量36的唯一数字:

Answer: 27 | 27 54 81 108 135 162 189 216 243 270 297 324 351 378 405
             432 459 486 513 540 567 594 621 648 675 702 729 756 783
             810 837 864 891 918 945 972

答案 3 :(得分:0)

如果你只是寻找最高的数字,你可以削减一些分支。从6 x 11 = 66开始,您也知道11的幅度最多为5.一旦您知道幅度> = 5的较高数字,您可以跳过11。

相关问题