生成所有字符串组合的算法

时间:2017-03-22 03:04:53

标签: string algorithm combinations permutation

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

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的解决方案,我将每个字母转换成一个节点并在相邻字符串中的所有字母之间创建连接,但这似乎太费力了。

3 个答案:

答案 0 :(得分:4)

在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

答案 1 :(得分:1)

从您的解决方案中,您似乎需要拥有与字符串一样多的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)

答案 2 :(得分:0)

以下是我在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;
}

基本上,我正在使用递归方法。我的基本情况是,当我的数组中没有剩余的单词时,在这种情况下,我只需在我的数组中为prefix + c(字符)添加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