【问题标题】:Algorithm for generating all string combinations生成所有字符串组合的算法
【发布时间】:2017-03-22 03:04:52
【问题描述】:

假设我有一个字符串列表,如下所示:

strings = ["abc", "def", "ghij"]

请注意,列表中字符串的长度可能会有所不同。

生成新字符串的方法是从列表的每个元素中按顺序取一个字母。示例:“adg”和“bfi”,但不是“dch”,因为这些字母与它们在列表中出现的顺序不同。因此,在我知道列表中只有三个元素的情况下,我可以很容易地使用嵌套的 for 循环结构生成所有可能的组合,如下所示:

for i in strings[0].length:
   for ii in strings[1].length:
      for iii in strings[2].length:
         print(i+ii+iii)

当我事先不知道字符串列表将有多长时,问题就出现了。如果列表有 n 个元素长,那么我的解决方案需要 n 个 for 循环才能成功。

谁能指出一个相对简单的解决方案?我正在考虑一个基于 DFS 的解决方案,我将每个字母变成一个节点,并在相邻字符串中的所有字母之间建立连接,但这似乎太费力了。

【问题讨论】:

  • 这是蟒蛇吗?它几乎看起来像 python...(除了我不知道 .length 在那里做什么)

标签: string algorithm combinations permutation


【解决方案1】:

在 python 中,你会使用itertools.product

例如:

>>> for comb in itertools.product("abc", "def", "ghij"):
>>>   print(''.join(comb))
adg
adh
adi
adj
aeg
aeh
...

或者,使用解包:

>>> words = ["abc", "def", "ghij"]
>>> print('\n'.join(''.join(comb) for comb in itertools.product(*words)))
(same output)

product 使用的算法非常简单,从它的源代码中可以看出(特别是函数product_next)。它基本上枚举了混合基系统中的所有可能数字(其中每个数字位置的乘数是相应单词的长度)。一个仅适用于字符串且不实现 repeat 关键字参数的简单实现可能是:

def product(words):
    if words and all(len(w) for w in words):
        indices = [0] * len(words)
        while True:
            # Change ''.join to tuple for a more accurate implementation
            yield ''.join(w[indices[i]] for i, w in enumerate(words))
            for i in range(len(indices), 0, -1):
                if indices[i - 1] == len(words[i - 1]) - 1:
                    indices[i - 1] = 0
                else:
                    indices[i - 1] += 1
                    break
            else:
                break

【讨论】:

  • 方便,但我不一定使用 Python,即使我的伪代码非常 Python 式。
  • @jimmy:很公平。很容易找到 itertools.product 的实现;我提供的链接中有一个,但我实际上并不建议使用它。这是一个更好的:stackoverflow.com/a/12605800/1566221
  • @Jimmy_Rustle:添加了一个实现fwiw。,
【解决方案2】:

从您的解决方案看来,您需要有与字符串一样多的 for 循环。对于您在最终字符串中生成的每个字符,您需要一个 for 循环遍历可能的字符列表。为此,您可以制定递归解决方案。每次你在递归中深入一层,你只需要运行一个for 循环。递归级别与字符串一样多。

下面是python中的一个例子:

strings = ["abc", "def", "ghij"]

def rec(generated, k):
    if k==len(strings):
        print(generated)
        return

    for c in strings[k]:
        rec(generated + c, k+1)

rec("", 0)

【讨论】:

    【解决方案3】:

    这是我在 Javascript 中的做法(我假设每个字符串都不包含重复字符):

    function getPermutations(arr)
    {
      return getPermutationsHelper(arr, 0, "");
    }
    
    function getPermutationsHelper(arr, idx, prefix)
    {
      var foundInCurrent = [];
      for(var i = 0; i < arr[idx].length; i++)
      {
        var str = prefix + arr[idx].charAt(i);
    
        if(idx < arr.length - 1)
        {
          foundInCurrent = foundInCurrent.concat(getPermutationsHelper(arr, idx + 1, str));
        }
        else
        {
          foundInCurrent.push(str);
        }
      }
      return foundInCurrent;
    }
    

    基本上,我使用的是递归方法。我的基本情况是当我的数组中没有更多单词时,在这种情况下,我只需为最后一个单词中的每个 c(字符)添加 prefix + c 到我的数组中。

    否则,我会尝试当前单词中的每个字母,并将我构建的前缀递归地传递给下一个单词。

    对于您的示例数组,我得到了:

    adg adh adi adj aeg aeh aei aej afg afh afi afj bdg bdh bdi 
    bdj beg beh bei bej bfg bfh bfi bfj cdg cdh cdi cdj ceg ceh 
    cei cej cfg cfh cfi cfj
    

    【讨论】:

      猜你喜欢
      • 2012-02-16
      • 2020-08-18
      • 1970-01-01
      • 2012-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-23
      相关资源
      最近更新 更多