获取包含Java中重复字符的字符串或组合的所有可能排列

时间:2011-02-25 04:44:25

标签: java combinations permutation

我一直在尝试生成每个可能的4个字符串的列表,该字符串可以由任何给定的字符集组成。我已经使用一个函数从一组字符生成每4个字符组合,但每个字符只使用一次。我需要使用给定的一组字符进行所有可能的组合,例如:

String[] elements = {"a", "b", "c", "1", "2", "3"};
int[] indices;
CombinationGenerator x = new CombinationGenerator (elements.length, 4);
StringBuffer combination;
while (x.hasMore ()) {
  combination = new StringBuffer ();
  indices = x.getNext ();
  for (int i = 0; i < indices.length; i++) {
      combination.append (elements[indices[i]]);
  }
  System.out.println (combination.toString ());
}

使用here中的CombinationGenerator类, 这将返回每个唯一的4个字符组合,例如:

'abcd' , 'abc1', 'acb2', 'acb1'

但是,我希望每个可能使用给定字符创建的字符串。例如:

'aaaa', 'aaab', 'abc1', 'aac1', '11c2'

我已经尝试了我能够找到或提出的每种递归和置换方法,但是我很难得到比上面所有组合更多的东西,然后生成每个组合的每个排列,但我可以找不到如何使用重复的字符创建一组组合。

任何帮助,甚至只是关于如何做到这一点的理论都会有所帮助。

5 个答案:

答案 0 :(得分:8)

您将需要更具体地了解您希望功能得到什么。 “组合”有许多不同的定义,您没有指定是否需要有序或无序组合。

数学上,如果你有n个元素,并且想要一个k的LIST(以重复排序),那就会给你

n ^ k

组合。 (原始示例中有6 ^ 4 = 1296种组合,这很多!)。但是,如果你有n个元素,并且想要一个k的MULTISET(重复无序),那么就会给你

(n + k - 1)! / (k! * (n - 1)!)

组合,是一个更难理解的枚举。

如果k很小,你可以用有限数量的for循环生成第一个,但随着k的增长,这变得非常麻烦。这强烈暗示需要RECURSIVE方法:

public static String[] getAllLists(String[] elements, int lengthOfList)
{
    //initialize our returned list with the number of elements calculated above
    String[] allLists = new String[(int)Math.pow(elements.length, lengthOfList)];

    //lists of length 1 are just the original elements
    if(lengthOfList == 1) return elements; 
    else
    {
        //the recursion--get all lists of length 3, length 2, all the way up to 1
        String[] allSublists = getAllLists(elements, lengthOfList - 1);

        //append the sublists to each element
        int arrayIndex = 0;

        for(int i = 0; i < elements.length; i++)
        {
            for(int j = 0; j < allSublists.length; j++)
            {
                //add the newly appended combination to the list
                allLists[arrayIndex] = elements[i] + allSublists[j];
                arrayIndex++;
            }
        }

        return allLists;
    }
}

此方法不仅会生成所有列表,还会按顺序枚举它们。也就是说,输出将是

aaaa
aaab
aaac
aaa1
aaa2
aaa3
aaba
aabb
aabc
aab1
...
3323
333a
333b
333c
3331
3332
3333

使用您的原始输入。它也可以生成任何长度的单词(对此非常小心!只需要长度为8的单词,我就会得到1,679,616个组合!)。

如果方法让您感到困惑(这是一种递归方法,因此有点难以理解),或者如果您想要解决第二个组合问题,请随意提问。此外,这种方法效率有点低,因为它重新计算了所有子列表的组合,因此对于很长的列表来说它不可行。如果你真的想要效率,你可以将已经计算过的元组存储在全局列表中。

答案 1 :(得分:5)

如果你想在Python中使用它,你不需要知道如何编程!

import itertools
for p in itertools.permutations('abc123', 4):
    print ''.join(p)

答案 2 :(得分:1)

递归解决方案似乎也非常简单:

public class TestCombinations {

public static void main(String[] args) {
    String[] elements = {"a", "b", "c", "1", "2", "3"};
    int maxLength = 4;
    combineStringFromElements(elements, "", maxLength);
}

private static void combineStringFromElements(String[] elements, String currentString, int maxLength) {
    if (currentString.length() == maxLength) {
        System.out.println(currentString);
        return;
    }
    for (String element : elements) {
        combineStringFromElements(elements, currentString + element, maxLength);
    }
}

}

代码既不干净也不高效,只是为了演示逻辑。

答案 3 :(得分:0)

您可以将元素视为数字。考虑如何通过计数得到“0” - “9”的所有可能组合。从0000,0001,0002,...,0010,0011等开始。使用相同的过程,就好像你有一个base-6数字系统(或base-n,其中n是你{{1}的长度} array。

elements

替换最后一位数字中的每个组合,然后前进数字并重复。当倒数第二个数字经过每个元素时,然后推进倒数第三个数字,依此类推。当你达到“3333”时,你就完成了。

您的代码将是这样的:

aaaa, aaab, aaac, ...,
aaba, aabb, aabc, aab1, aab2, aab3, .....,
aa32, aa33, abaa, etc.

还有其他方法可以实现更高效的相同操作,例如存储中间的1,2,3字符字符串。还有递归解决方案。但这是一般性的想法,对于您现在使用的数据大小应该足够快(您总共有string comb; for (int i = 0; i < elements.length; i++) for (int j = 0; j < elements.length; j++) for (int k = 0; k < elements.length; k++) for (int m = 0; m < elements.length; m++) { comb = elements[i] + elements[j] + elements[k] + elements[m]; // do something with the combination } 个组合。

答案 4 :(得分:0)

以下是一些符合您需要的python代码:

answer = []
def permute(chars, s=''):
    if len(s) == 4:
        answer.append(s)
    else:
        for char in chars:
            permute(chars, s+char)

希望这有帮助

这种类型的算法称为recursive descent,以防您尚未检查过。