java - 没有重复元素的字符串排列

时间:2016-04-06 21:39:49

标签: java algorithm unique permutation

我正在使用此代码https://stackoverflow.com/a/4240323/2655623来创建排列并对每个结果进行一些计算。

public static void permutation(String str) { 
    permutation("", str); 
}

private static void permutation(String prefix, String str) {
    int n = str.length();

    int p = prefix.length();
    if(p==5){
            //do some calculation for |prefix| = 5
            return;
    }
    for (int i = 0; i < n; i++){
            permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i+1, n));
    }
}

这个算法对我很有用。但是,我想看看我如何删除重复的字符,所以我不再计算前缀。例如

permutation("aacccbbdeeeef");

我将处理 abcde 关于

A = 2 * 4*3*2*1 when a----
B = 2 * 4*3*2*1 when b----
C = 3 * 4*3*2*1 when c----
and so on...
// I hope you get the idea

我想知道我是否可以减少重复计算的数量。

我认为的一种方法是对字符顺序进行排序,并在我为其使用FOR时仅计算每个重复字符中的一个。

for (int i = 0; i < n; i++){
    if(i>0 && str.charAt(i) == str.charAt(i-1)) continue;
    permutation.....
}

这对我来说很好,因为只需要一次排列。当重复字母数很高时,它会大大减少调用次数。

现在,总结一下,我想知道是否

  1. 这个保证比我不会错过任何排列吗?
  2. 如何防止像(1)ba(2)cd和(2)ba(1)cd这样的情况 当p = 5时发生。至于p = 8或10,我使用的技巧将不那么有效。那么我需要做什么?
  3. 非常感谢。

4 个答案:

答案 0 :(得分:2)

  1.   

    这是保证,我不会错过任何排列吗?

  2. 是。如果所有重复的字符都在块中,例如"aaabbccccc",那么代码行

    if(i>0 && str.charAt(i) == str.charAt(i-1)) continue;
    

    正是您所需要的。它不会错过任何排列,因为它只会跳过那些本来会相同的排列。并且它不会重复任何排列,因为相等的字符是块。

    1.   

      如何防止像(1)ba(2)cd和a(2)ba(1)cd这样的情况   当p = 5时发生。至于p = 8或10,我使用的技巧不会   那很有效率。那我需要做什么?

    2. 我认为不需要担心像"abacd"这样的输入字符串。此字符串的排列集与"aabcd"的集合完全相同,因此在开头对字符串进行排序是有意义的(这会将重复的字符收集到块中),并调用permutation("", sortedString);。这样做你可以使用你提到的技巧。

      对于长字符串,它总是很慢,因为有很多排列,也因为该方法创建了大量的字符串对象。这些因素更为重要,因为通过迭代比严格必要的范围稍大且使用continue而产生的次要低效率。

答案 1 :(得分:0)

简单的解决方案是将字符存储到Set中(删除重复项)并读取它们;)

答案 2 :(得分:0)

public static void permutation(String str) { 
    Set<Character> charsSet = new HashSet<Character>();
    for (int i = 0; i < s.length(); i++){
        Character  c = new Character (s.charAt(i));
        charsSet.add(c);   
    }
    StringBuilder sb = new StringBuilder();
    for (Character  c : charsSet) {
        sb.append(c.charValue());
    }
    permutation("", sb.toString()); 
}

private static void permutation(String prefix, String str) {
    int n = str.length();

    int p = prefix.length();
    if(p==5){
            //do some calculation for |prefix| = 5
            return;
    }
    for (int i = 0; i < n; i++){
            permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i+1, n));
    }
}

答案 3 :(得分:0)

这是我的“长度为n的总有符号排列”的变体

样本数据集

2

示例输出

-1 -2

-1 2

1 -2

1 2

-2 -1

-2 1

2 -1

2 1

总计:8

请遵循以下示例:

private static int count = 0;

@Test
public void unsignedPermTest(){
    final int unsigendN = 2;
    final int n = unsigendN * 2;

    final int[] arr = new int[n];

    for(int i=1; i<=unsigendN;i++){
        arr[i-1] = i;
        arr[arr.length-i] = -i;
    }

    count = 0;
    permutation(arr, n, unsigendN);
    System.out.println("total: " + count);
}

public static void permutation(final int[] arr, final int n, final int k) {
    permutation(arr, "", n, k);
}

private static void permutation(final int[] arr, final String prefix, final int n, final int k) {

    if (k == 0)
    {
        final String res = prefix.substring(1);

        final String[] chars = res.split(" ");

        for(int i=0; i<chars.length;i++){
            for(int j=i+1; j<chars.length;j++){
                if(chars[i].replace("-", "").equals(chars[j].replace("-", ""))) return;
            }
        }

        count=count+1;
        System.out.println(res);
        return;
    }

    for (int i = 0; i < n; ++i) {
        permutation(arr, prefix + " " + arr[i], n, k - 1);
    }
}