找到 0、1 的所有组合,总和为 1 或 2,长度/大小不同

Find all combinations of 0, 1 that sum to 1 or 2 at varying lengths / sizes

我想要一个 return 0、1 组合的函数,总和为 1 或 2,长度不一。 我知道总组合(在删除求和之前)遵循 2**length.

示例: 长度 = 4

结果:

[[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 0, 1, 1],
[0, 1, 0, 0],
[0, 1, 0, 1],
[0, 1, 1, 0],
[1, 0, 0, 0],
[1, 0, 0, 1],
[1, 0, 1, 0],
[1, 1, 0, 0]]

我能够使用递归函数得到最多 10 的长度。 之后,python 由于递归限制而崩溃。

我确实尝试增加它,但这仍然导致程序崩溃。我希望能够进行总和为 1 或 2 的所有组合,最长为 40。

代码如下:

def recursive_comb(bits):
     """Creates all possible combinations of 0 & 1
     for a given length
     """
     test = []

     def calc_bits(bits, n=0):
         if n.bit_length() <= bits:
             comb_str = '{:0{}b}'.format(n, bits)
             comb_list = [int(elem) for elem in comb_str]
             test.append(comb_list) 
             calc_bits(bits, n + 1)

     calc_bits(bits)

     return test

all_comb = recursive_comb(4)

all_comb = [elem for elem in all_comb if ((sum(elem) == 1) or (sum(elem) == 2))]

你可以简单地这样做:

from itertools import permutations

length = 4
result = {p for p in permutations([0, 1]*length, length) if sum(p) in [1, 2]}

print(result)

# output:
# {(0, 0, 0, 1),
#  (0, 0, 1, 0),
#  (0, 0, 1, 1),
#  (0, 1, 0, 0),
#  (0, 1, 0, 1),
#  (0, 1, 1, 0),
#  (1, 0, 0, 0),
#  (1, 0, 0, 1),
#  (1, 0, 1, 0),
#  (1, 1, 0, 0)}

结果集包含总和为 1 或 2 的所有排列。

permutations 中进行了一些冗余计算,因此可能需要一段时间,具体取决于 length,但您不应该 运行 陷入递归/内存错误。

如果您不介意使用外部库 (sympy),您可以使用这个:

from sympy.utilities.iterables import multiset_permutations

length = 4
for n in range(1, 3):
    lst = [1] * n + [0] * (length - n)
    for perm in multiset_permutations(lst):
        print(perm)

multiset_permutations 生成列表的所有不同排列,其中元素不是成对不同的。我将其用于具有所需数量 01 的列表。

如果您的列表包含许多元素,这将更有效,只需遍历所有可能的排列并使用 set 丢弃重复项。

这是 itertools 的另一个解决方案。对于每个长度 n,以 combinations(n, k) 种方式选择 k 个位置。这种方法不太通用 multiset_permutations 来自 sympy,但对于这种特定情况更快:

import itertools

# notation:
# n: length of a sequence
# k: number of ones

def f(n, ks):
  for k in ks:
    for idx in itertools.combinations(range(n), k):
      buf = [0] * n
      for i in idx:
        buf[i] = 1
      yield buf

result = list(f(4, [1,2]))

与 20 倍加速的比较:

from sympy.utilities.iterables import multiset_permutations


def g(n, ks):
  length = n
  for k in ks:
    lst = [1] * k + [0] * (n - k)
    for perm in multiset_permutations(lst):
        yield(perm)

assert sum(1 for _ in f(20, [1,2,3])) == sum(1 for _ in g(20, [1,2,3]))
%timeit sum(1 for _ in g(20, [1,2,3])) # 10ms
%timeit sum(1 for _ in f(20, [1,2,3])) # 500µs