【问题标题】:java - string permutation without duplication elementsjava - 没有重复元素的字符串排列
【发布时间】:2016-04-06 21:39:49
【问题描述】:

我正在使用此代码 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. 如何防止像 a(1)ba(2)cd 和 a(2)ba(1)cd 这样的情况 当 p=5 时发生。至于 p=8 或 10,我使用的技巧不会那么有效。那我需要做什么?

非常感谢。

【问题讨论】:

    标签: java algorithm unique permutation


    【解决方案1】:
    1. 这是保证我不会错过任何排列吗?

    是的。如果所有重复的字符都在块中,如"aaabbccccc",则该行代码

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

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

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

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

    对于长字符串,无论如何它都会很慢,因为有很多排列,也因为该方法创建了很多字符串对象。这些因素比使用continue 在比严格必要的稍大的范围内迭代所产生的轻微低效率更为重要。

    【讨论】:

    • 感谢您的帮助。我想我必须找到一种方法来减少将生成的字符串数量。我想知道我是否可以使用交换方法一次只更改一个字符并将所有更改保存在 char[] 变量中。我以某种方式在我的计算中做到了,它将计算时间从 800 毫秒大幅减少到 16 毫秒,这对我来说是一个巨大的进步。
    【解决方案2】:

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

    【讨论】:

    • 我正在考虑,但是这需要的时间和空间很大,在繁忙的服务器上我负担不起。
    【解决方案3】:
    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));
        }
    }
    

    【讨论】:

    • 这将删除重复的字符,它也会缩短排列。对于 str=aaabbbbbb,它将生成 'ab' 的序列,它是来自输入字符串的另一个字符串。这是一个算法错误。
    【解决方案4】:

    这是我对“长度为 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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-30
      • 2020-07-23
      • 2022-01-27
      • 1970-01-01
      • 2017-02-18
      • 1970-01-01
      相关资源
      最近更新 更多