1

例如,给定两个字母 A 和 B,我想生成所有长度为 n 且具有 x A 和 y B 的字符串。

我希望这能有效地完成。我考虑过的一种方法是构建一个长度为 x 的 A 列表,然后以各种可能的方式将 y B 插入到列表中。但是插入 python 列表是线性的,所以当列表变大时,这种方法会很糟糕。

性能目标(这可能不合理,但这我的希望):在不到一分钟的时间内生成所有长度为 20 且 A 和 B 数量相等的字符串。

编辑:建议使用 permutations('A' * x, 'B' * y) 。虽然不是一个坏主意,但它浪费了很多。如果 x = y = 4,您将多次生成字符串 'AAAABBBB'。有没有更好的方法可以只生成每个字符串一次?我已经尝试了 set(permutations('A' * x, 'B' * y)) 效果的代码,它太慢了。

4

3 回答 3

3

一个简单的方法如下:

import itertools

def make_sequences(x, y):
    return set(itertools.permutations("A" * x + "B" * y))

itertools.permutations()函数不考虑输入列表中的重复元素。它最终生成与先前生成的排列重复的排列。因此,使用set()构造函数会删除结果中的重复元素。

于 2012-05-02T23:05:32.047 回答
3

关于您对性能的担忧,这里是您的想法的实际生成器实现(不带insert)。它找到相应的位置B并填写列表。

import itertools

def make_sequences(num_a, num_b):
    b_locations = range(num_a+1)
    for b_comb in itertools.combinations_with_replacement(b_locations, num_b):
        result = []
        result_a = 0
        for b_position in b_comb:
            while b_position > result_a:
                result.append('A')
                result_a += 1
            result.append('B')
        while result_a < num_a:
            result.append('A')
            result_a += 1
        yield ''.join(result)

它确实表现更好。与Greg Hewgill的解决方案(命名make_sequences2)比较:

In : %timeit list(make_sequences(4,4))
10000 loops, best of 3: 145 us per loop

In : %timeit make_sequences2(4,4)
100 loops, best of 3: 6.08 ms per loop

编辑

通用版本:

import itertools

def insert_letters(sequence, rest):
    if not rest:
        yield sequence
    else:
        letter, number = rest[0]
        rest = rest[1:]
        possible_locations = range(len(sequence)+1)
        for locations in itertools.combinations_with_replacement(possible_locations, number):
            result = []
            count = 0
            temp_sequence = sequence
            for location in locations:
                while location > count:
                    result.append(temp_sequence[0])
                    temp_sequence = temp_sequence[1:]
                    count += 1
                result.append(letter)
            if temp_sequence:
                result.append(temp_sequence)
            for item in insert_letters(''.join(result), rest):
                yield item

def generate_sequences(*args):
    '''
    arguments : squence of (letter, number) tuples
    '''
    (letter, number), rest = args[0], args[1:]
    for sequence in insert_letters(letter*number, rest):
        yield sequence

用法:

for seq in generate_sequences(('A', 2), ('B', 1), ('C', 1)):
    print seq

# Outputs
# 
# CBAA
# BCAA
# BACA
# BAAC
# CABA
# ACBA
# ABCA
# ABAC
# CAAB
# ACAB
# AACB
# AABC
于 2012-05-02T23:37:27.013 回答
1

这应该会给你一个想法(我已经包含了每个步骤,所以你可以看到发生了什么):

>>> x = 2
>>> y = 3
>>> lst_a = ['A'] * x
>>> lst_b = ['B'] * y
>>> print lst_a, lst_b
['A', 'A'] ['B', 'B', 'B']
>>> lst_a.extend(lst_b)
>>> lst_a
['A', 'A', 'B', 'B', 'B']
>>> print list(itertools.permutations(lst_a))
于 2012-05-02T23:06:02.783 回答