Python-使用特定字母表中的n个替换项构建特定长度的新字符串

Python-使用特定字母表中的n个替换项构建特定长度的新字符串,python,itertools,Python,Itertools,我一直在研究一种快速、有效的方法来解决以下问题,但到目前为止,我只能使用一种相当缓慢的嵌套循环解决方案来解决它。无论如何,以下是描述: 所以我有一个长度为L的字符串,比如说'BBBX'。我想找到所有可能的长度为L的字符串,从'BBBX'开始,它们最多相差2个位置,至少相差0个位置。此外,在构建新字符串时,必须从特定的字母表中选择新字符 我猜字母表的大小无关紧要,所以在这种情况下,让我们假设字母表是['B','G','C','X'] 因此,一些示例输出将是,'BGBG','BGBC','BBGX'

我一直在研究一种快速、有效的方法来解决以下问题,但到目前为止,我只能使用一种相当缓慢的嵌套循环解决方案来解决它。无论如何,以下是描述:

所以我有一个长度为L的字符串,比如说
'BBBX'
。我想找到所有可能的长度为L的字符串,从
'BBBX'
开始,它们最多相差2个位置,至少相差0个位置。此外,在构建新字符串时,必须从特定的字母表中选择新字符

我猜字母表的大小无关紧要,所以在这种情况下,让我们假设字母表是
['B','G','C','X']

因此,一些示例输出将是,
'BGBG'
'BGBC'
'BBGX'
,等等。对于长度为4的字符串,最多有2个替换,我的算法会找到67个可能的新字符串


我一直在尝试使用
itertools
来解决这个问题,但我在找到解决方案时遇到了一些困难。我尝试使用
itertools.compositions(范围(4),2)
找到所有可能的位置。然后我考虑使用
itertools
中的
product()
来构建所有的可能性,但我不确定是否有一种方法可以以某种方式将其连接到
组合()输出的索引

测试不多,但对于您给出的示例,它确实找到了67。将索引连接到产品的简单方法是通过
zip()

注意:与FogleBird的主要区别在于我首先发布了-LOL;-)算法非常相似。Mine将输入构造为
product()
,这样就不会试图用字母替换自己;FogleBird允许“身份”替换,但会计算进行了多少有效替换,如果发生任何身份替换,则会将结果丢弃。对于较长的单词和大量的替换,这可能会慢得多(可能是
len(alphabet)**nsubs
(len(alphabet)-1)**nsubs
…in product():
循环中的时间不同)。

这是我的解决方案

第一个for循环告诉我们将执行多少次替换。(0、1或2-我们逐一检查)

第二个循环告诉我们将更改哪些字母(通过它们的索引)

第三个循环遍历这些索引中所有可能的字母更改。有一些逻辑来确保我们确实更改了字母(将“C”更改为“C”不算)

以下是它的输出:

BBBX GBBX CBBX XBBX BGBX BCBX BXBX BBGX BBCX BBXX BBBB BBBG BBBC GGBX
GCBX GXBX CGBX CCBX CXBX XGBX XCBX XXBX GBGX GBCX GBXX CBGX CBCX CBXX
XBGX XBCX XBXX GBBB GBBG GBBC CBBB CBBG CBBC XBBB XBBG XBBC BGGX BGCX
BGXX BCGX BCCX BCXX BXGX BXCX BXXX BGBB BGBG BGBC BCBB BCBG BCBC BXBB
BXBG BXBC BBGB BBGG BBGC BBCB BBCG BBCC BBXB BBXG BBXC
import itertools

def generate_replacements(lo, hi, alphabet, text):
    for count in range(lo, hi + 1):
        for indexes in itertools.combinations(range(len(text)), count):
            for letters in itertools.product(alphabet, repeat=count):
                new_text = list(text)
                actual_count = 0
                for index, letter in zip(indexes, letters):
                    if new_text[index] == letter:
                        continue
                    new_text[index] = letter
                    actual_count += 1
                if actual_count == count:
                    yield ''.join(new_text)

for text in generate_replacements(0, 2, 'BGCX', 'BBBX'):
    print text
BBBX GBBX CBBX XBBX BGBX BCBX BXBX BBGX BBCX BBXX BBBB BBBG BBBC GGBX
GCBX GXBX CGBX CCBX CXBX XGBX XCBX XXBX GBGX GBCX GBXX CBGX CBCX CBXX
XBGX XBCX XBXX GBBB GBBG GBBC CBBB CBBG CBBC XBBB XBBG XBBC BGGX BGCX
BGXX BCGX BCCX BCXX BXGX BXCX BXXX BGBB BGBG BGBC BCBB BCBG BCBC BXBB
BXBG BXBC BBGB BBGG BBGC BBCB BBCG BBCC BBXB BBXG BBXC