【问题标题】:Find all permutations of numbers of exactly 9 characters long查找长度正好为 9 个字符的数字的所有排列
【发布时间】:2021-05-27 21:31:16
【问题描述】:

我有号码[0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 15, 16]

我想找出正好是 9 个字符的数字的所有排列。例如,如果我有 8 个个位数,最后一个不能是两位数,因为它会超出字符数限制。

说明:

  • 同一个号码可以重复使用,例如号码 1 九次有效。
  • 可以有任意数量的两位数字,只要数字的总字符长度正好是 9。例如,1、10、12、15、16 有效。

我尝试了itertools.permutations,但无法使用两位数。

【问题讨论】:

  • 所以您还想要少于 9 个字符的数字组合?也就是说,您是否希望 0 成为有效组合?还是您想要正好 9 个字符?
  • 我不明白你的任务是什么。你能举几个例子吗?
  • 号码可以重复使用吗?
  • 如果我正确理解您的要求,唯一麻烦的两位数是 15,因为其他都是有效的 1 位数字的组合。
  • @mkrieger1 我认为他们的意思是0, 1, 2, 3, 4, 6, 7, 10 是一个有效的排列,但0, 1, 2, 3, 4, 6, 10, 12 不是

标签: python permutation


【解决方案1】:

我会使用组合和排列的混合。

首先找到加起来达到所需长度的所有数据组合。然后对于每个独特的组合,找到它们的排列。这里可能需要做一些工作来限制检查的错误组合的数量:

import itertools


def perm_of_length(data, length):
    for i in range(len(data)):
        for comb in itertools.combinations(data, i + 1):
            if sum(map(len, (map(str, comb)))) == length:
                for perm in itertools.permutations(comb):
                    yield perm


for perm in perm_of_length([0, 1, 2, 3, 10, 12], 4):
    print(perm)

输出:

(10, 12)
(12, 10)
(0, 1, 10)
(0, 10, 1)
(1, 0, 10)
(1, 10, 0)
(10, 0, 1)
(10, 1, 0)
(0, 1, 12)
(0, 12, 1)
(1, 0, 12)
(1, 12, 0)
(12, 0, 1)
(12, 1, 0)
(0, 2, 10)
(0, 10, 2)
(2, 0, 10)
(2, 10, 0)
(10, 0, 2)
(10, 2, 0)
(0, 2, 12)
(0, 12, 2)
(2, 0, 12)
(2, 12, 0)
(12, 0, 2)
(12, 2, 0)
(0, 3, 10)
(0, 10, 3)
(3, 0, 10)
(3, 10, 0)
(10, 0, 3)
(10, 3, 0)
(0, 3, 12)
(0, 12, 3)
(3, 0, 12)
(3, 12, 0)
(12, 0, 3)
(12, 3, 0)
(1, 2, 10)
(1, 10, 2)
(2, 1, 10)
(2, 10, 1)
(10, 1, 2)
(10, 2, 1)
(1, 2, 12)
(1, 12, 2)
(2, 1, 12)
(2, 12, 1)
(12, 1, 2)
(12, 2, 1)
(1, 3, 10)
(1, 10, 3)
(3, 1, 10)
(3, 10, 1)
(10, 1, 3)
(10, 3, 1)
(1, 3, 12)
(1, 12, 3)
(3, 1, 12)
(3, 12, 1)
(12, 1, 3)
(12, 3, 1)
(2, 3, 10)
(2, 10, 3)
(3, 2, 10)
(3, 10, 2)
(10, 2, 3)
(10, 3, 2)
(2, 3, 12)
(2, 12, 3)
(3, 2, 12)
(3, 12, 2)
(12, 2, 3)
(12, 3, 2)
(0, 1, 2, 3)
(0, 1, 3, 2)
(0, 2, 1, 3)
(0, 2, 3, 1)
(0, 3, 1, 2)
(0, 3, 2, 1)
(1, 0, 2, 3)
(1, 0, 3, 2)
(1, 2, 0, 3)
(1, 2, 3, 0)
(1, 3, 0, 2)
(1, 3, 2, 0)
(2, 0, 1, 3)
(2, 0, 3, 1)
(2, 1, 0, 3)
(2, 1, 3, 0)
(2, 3, 0, 1)
(2, 3, 1, 0)
(3, 0, 1, 2)
(3, 0, 2, 1)
(3, 1, 0, 2)
(3, 1, 2, 0)
(3, 2, 0, 1)
(3, 2, 1, 0)

证明这是有效的:

for perm in perm_of_length([0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 15, 16], 9):
    assert sum(map(len, map(str, perm))) == 9

【讨论】:

  • 在将 == 更改为 <= 后,似乎给出了与我的蛮力方法相同的结果,但要快得多。
  • @MateenUlhaq 啊,有趣。不太确定它会如何匹配。
  • cmets中的OP声明数字可以重复使用,所以这似乎缺少很多解决方案。但后来他将其标记为已接受,所以我放弃了尝试理解它。
【解决方案2】:

注意:这比它需要的要慢得多。


一种简单的、非性能的、带有过滤的蛮力方法:

symbols = [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 15, 16]
symbols = [str(x) for x in symbols]
perms = itertools.chain.from_iterable(
    itertools.permutations(symbols, i) for i in range(10)
)
perms = ("".join(x) for x in perms)
perms = [x for x in perms if len(x) <= 9]

>>> len(perms)
13600046

>>> perms[:4]
['', '0', '1', '2']

>>> perms[-4:]
['987643102', '987643120', '987643201', '987643210']

只需跳过perms 中的第一项即可删除空字符串。


不使用字符串的类似方法:

symbols = [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 15, 16]
lengths = {k: int(math.log10(k)) + 1 if k != 0 else 1 for k in symbols}
perms = itertools.chain.from_iterable(
    itertools.permutations(symbols, i) for i in range(10)
)
perms = [x for x in perms if sum(lengths[k] for k in x) <= 9]

>>> len(perms)
13600046

如果数字可以重复使用(如 cmets 中所述),我会考虑使用 itertools.product 而不是 itertools.permutations

symbols = [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 15, 16]
lengths = {k: int(math.log10(k)) + 1 if k != 0 else 1 for k in symbols}
perms = itertools.product(symbols, repeat=9)
perms = [x for x in perms if sum(lengths[k] for k in x) <= 9]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-14
    • 2015-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-17
    • 2015-12-28
    • 2013-12-14
    相关资源
    最近更新 更多