【问题标题】:generating Variations without repetitions / Permutations in java在java中生成没有重复/排列的变化
【发布时间】:2009-12-14 10:53:55
【问题描述】:

我必须生成所有变体,而不是重复数字 0 - 9。

它们的长度可以从1到10。我真的不知道如何解决它,尤其是如何避免重复。

示例: 变化长度:4 随机变化:9856、8753、1243、1234 等(但不是 9985 - 包含重复)

如果有人能帮助我解决这个问题,我将非常感激,尤其是提供一些代码和线索。

【问题讨论】:

    标签: java algorithm permutation variations


    【解决方案1】:

    要查找的关键字是排列。有大量免费的源代码可以执行它们。

    至于保持它不重复,我建议一种简单的递归方法:对于每个数字,您可以选择是否将其纳入您的变体中,因此您的递归通过数字计数并分叉为两个递归调用,其中digit 被包括在内,其中一位被排除在外。然后,在你到达最后一个数字之后,每个递归基本上都会给你一个(唯一的、排序的)无重复数字的列表。然后,您可以创建此列表的所有可能排列,并组合所有这些排列以获得最终结果。

    (和 duffymo 说的一样:我不会为此提供代码)

    高级说明:递归基于 0/1(排除、包含),可以直接转换为位,因此是整数。因此,为了在不实际执行递归的情况下获得所有可能的数字组合,您可以简单地使用所有 10 位整数并遍历它们。然后解释这些数字,使得一个设置位对应于包括需要置换的列表中的数字。

    【讨论】:

    • 我不明白这个解决方案。听起来您正在生成给定集合的所有子集。你如何从子集到排列?
    • 如上所述,此解决方案强调如何获取数字集并将其用作生成所有相应排列的输入。如何实际生成排列不在此范围内,但相关资源非常丰富。
    【解决方案2】:

    这是我的 Java 代码。如果您不明白,请随时询问。这里的重点是:

    1. 重新排序字符数组。例如:a1 a2 a3 b1 b2 b3 .... (a1 = a2 = a3)
    2. 生成排列并始终保持条件:a1 的索引
    import java.util.Arrays;
    
    public class PermutationDup {
    
        public void permutation(String s) {
            char[] original = s.toCharArray();
            Arrays.sort(original);
            char[] clone = new char[s.length()];
            boolean[] mark = new boolean[s.length()];
            Arrays.fill(mark, false);
            permute(original, clone, mark, 0, s.length());
        }
    
        private void permute(char[] original, char[] clone, boolean[] mark, int length, int n) {
            if (length == n) {
                System.out.println(clone);
                return;
            }
    
            for (int i = 0; i < n; i++) {
                if (mark[i] == true) continue;
                // dont use this state. to keep order of duplicate character
                if (i > 0 && original[i] == original[i-1] && mark[i-1] == false) continue;
                mark[i] = true;
                clone[length] = original[i];
                permute(original, clone, mark, length+1, n);
                mark[i] = false;
            }
    
        }
    
        public static void main(String[] args) {
            PermutationDup p = new PermutationDup();
            p.permutation("abcab");
        }
    }
    

    【讨论】:

    • 如果我们想要得到长度为
    【解决方案3】:

    我创建了以下代码,用于生成排序很重要且不重复的排列。它利用泛型来置换任何类型的对象:

    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    public class Permutations {
    
        public static <T> Collection<List<T>> generatePermutationsNoRepetition(Set<T> availableNumbers) {
            Collection<List<T>> permutations = new HashSet<>();
    
            for (T number : availableNumbers) {
                Set<T> numbers = new HashSet<>(availableNumbers);
                numbers.remove(number);
    
                if (!numbers.isEmpty()) {
                    Collection<List<T>> childPermutations = generatePermutationsNoRepetition(numbers);
                    for (List<T> childPermutation : childPermutations) {
                        List<T> permutation = new ArrayList<>();
                        permutation.add(number);
                        permutation.addAll(childPermutation);
                        permutations.add(permutation);
                    }
                } else {
                    List<T> permutation = new ArrayList<>();
                    permutation.add(number);
                    permutations.add(permutation);
                }
            }
    
            return permutations;
        }
    }
    

    【讨论】:

      【解决方案4】:

      想象一下你有一个神奇的函数——给定一个数字数组,它会返回正确的排列。

      你如何使用这个函数来生成一个新的排列列表,只需要一个额外的数字?

      例如,

      如果我给你一个名为permute_three(char[3] digits)的函数,我告诉你它只适用于数字012,你怎么能写一个可以置换0、@的函数987654326@,23,使用给定的permute_three函数?

      ...

      一旦你解决了这个问题,你会注意到什么?你能概括一下吗?

      【讨论】:

      • 对于 OP:这里涉及的魔法也称为“递归”。
      • 我希望不要使用 r 这个词,因为它有时会吓到刚开始的人......
      【解决方案5】:

      使用Dollar 很简单:

      @Test
      public void generatePermutations() {
          // digits is the string "0123456789"
          String digits = $('0', '9').join();
      
          // then generate 10 permutations
          for (int i : $(10)) {
              // shuffle, the cut (0, 4) in order to get a 4-char permutation
              System.out.println($(digits).shuffle().slice(4));
          }
      }
      

      【讨论】:

      • Dollar 的链接现在已断开。我希望您能找到损坏的链接的替代品。 ://
      【解决方案6】:

      此代码类似于没有重复的代码,但添加了 if-else 语句。检查此code

      在上面的代码中,修改for循环如下

      for (j = i; j <= n; j++)
      {
      
      if(a[i]!=a[j] && !is_duplicate(a,i,j))              
          {
              swap((a+i), (a+j));
              permute(a, i+1, n);
              swap((a+i), (a+j)); 
          }
          else if(i!=j)  {}  // if no duplicate is present , do nothing           
          else permute(a,i+1,n);  // skip the ith character
      }
      
      bool is_duplicate(int *a,int i,int j) 
      {
           if a[i] is present between a[j]...a[i] 
              return 1;
          otherwise
              return 0;
      
      }
      

      为我工作

      【讨论】:

        【解决方案7】:

        没有重复的排列是基于定理,结果的数量是元素计数的阶乘(在这种情况下是数字)。在你的情况下 10!是10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = 3628800。为什么它完全正确的证明也是生成的正确解决方案。 那么怎么样。在第一个位置,即从左起你可以有 10 个数字,在第二个位置你只能有 9 个数字,因为一个数字在左边的位置,我们不能重复相同的数字等等。(证明是通过数学归纳法完成的)。 那么如何生成前十个结果呢?据我所知,他最简单的方法是使用循环移位。这意味着数字的顺序在一个位置向左移动(如果需要,也可以向右移动),溢出的数字放在空的地方。 这意味着前十个结果:

        10 9 8 7 6 5 4 3 2 1
        9 8 7 6 5 4 3 2 1 10
        8 7 6 5 4 3 2 1 10 9
        7 6 5 4 3 2 1 10 9 8
        6 5 4 3 2 1 10 9 8 7
        5 4 3 2 1 10 9 8 7 6
        ...

        第一行是基本样本,所以最好在生成之前将其放入集合中。好处是,在下一步中,您将必须解决相同的问题以避免不必要的重复。

        在下一步中,仅将 10-1 个数字递归旋转 10-1 次等。 这意味着第二步中的前 9 个结果:

        10 9 8 7 6 5 4 3 2 1
        10 8 7 6 5 4 3 2 1 9
        10 7 6 5 4 3 2 1 9 8
        10 6 5 4 3 2 1 9 8 7
        10 5 4 3 2 1 9 8 7 6
        ...

        等等,请注意,第一行来自上一步,因此不得再次将其添加到生成的集合中。

        算法递归地做到这一点,正如上面解释的那样。可以为 10! 生成所有 3628800 个组合,因为嵌套的数量与数组中的元素数量相同(这意味着在你的情况下,对于 10 个数字,它在我的计算机上徘徊大约 5 分钟)并且你需要有足够的内存如果您想将所有组合保留在数组中。

        有解决办法。

        package permutation;
        
        /** Class for generation amount of combinations (factorial)
         * !!! this is generate proper permutations without repeating and proper amount (počet) of rows !!!
         *
         * @author hariprasad
         */
        public class TestForPermutationII {
          private static final String BUMPER = "*";
          private static int counter = 0;
          private static int sumsum = 0;
          // definitoin of array for generation
          //int[] testsimple = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
          int[] testsimple = {1, 2, 3, 4, 5};
          private int ELEMNUM = testsimple.length;
          int[][] shuff;
        
          private String gaps(int len) {
            String addGap = "";
            for(int i=0; i <len; i++)
              addGap += "  ";
            return addGap;
          }
        
          /** Factorial computing */
          private int fact(int num) {
            if (num > 1) {
              return num * fact(num - 1);
            } else {
              return 1;
            }
          }
        
          /** Cyclic shift position to the left */  
          private int[] lShiftPos(int[] arr, int pos) {
            int[] work = new int[ELEMNUM];
            int offset = -1;
            for (int jj = 0; jj < arr.length; jj++) {
              if (jj < pos) {
                work[jj] = arr[jj];
              } else if (jj <= arr.length - 1) {
                if (jj == pos) {
                  offset = arr[pos]; // last element
                }
                if (jj != (arr.length - 1)) {
                  work[jj] = arr[jj + 1];
                } else {
                  work[jj] = offset;
                }
              }
            }
            return work;
          }
        
          private String printBuff(int[] buffer) {
            String res = "";
            for (int i= 0; i < buffer.length; i++) {
              if (i == 0) 
                res += buffer[i];
              else
                res += ", " + buffer[i];
            }
            return res;
          };
        
          /** Recursive generator for arbitrary length of array */
          private String permutationGenerator(int pos, int level) {
            String ret = BUMPER;
            int templen = counter;
            int[] work = new int[ELEMNUM];
            int locsumread = 0;
            int locsumnew = 0;
            //System.out.println("\nCalled level: " + level);
        
            for (int i = 0; i <= templen; i++) {
              work = shuff[i];
              sumsum++;
              locsumread++;
              for (int ii = 0; ii < pos; ii++) {
                counter++;
                sumsum++;
                locsumnew++;
                work = lShiftPos(work, level); // deep copy
                shuff[counter] = work;
              }
            }
        
            System.out.println("locsumread, locsumnew: " + locsumread + ", " + locsumnew);
            // if level == ELEMNUM-2, it means no another shift
            if (level < ELEMNUM-2) {
              ret = permutationGenerator(pos-1, level+1);
              ret = "Level " + level + " end.";
              //System.out.println(ret);
            }
            return ret;
          }
        
          public static void main(String[] argv) {
            TestForPermutationII test = new TestForPermutationII();
            counter = 0;
            int len = test.testsimple.length;
            int[] work = new int[len];
        
            test.shuff = new int[test.fact(len)][];
        
            //initial
            test.shuff[counter] = test.testsimple;
            work = test.testsimple; // shalow copy
        
            test.shuff = new int[test.fact(len)][];
            counter = 0;
            test.shuff[counter] = test.testsimple;
            test.permutationGenerator(len-1, 0);
        
            for (int i = 0; i <= counter; i++) {
              System.out.println(test.printBuff(test.shuff[i]));
            }
        
            System.out.println("Counter, cycles: " + counter + ", " + sumsum);
          }
        }
        

        算法的强度(循环数)是成员数的不完全阶乘之和。所以当再次读取部分集以生成下一个子集时存在悬垂,因此强度为:

        n! + n!/2! + n!/3! + ... + n!/(n-2)! + n!(n-1)!

        【讨论】:

          【解决方案8】:

          有一个解决方案不是我的,但它非常好和复杂。

              package permutations;
          
          import java.util.HashSet;
          import java.util.LinkedList;
          import java.util.List;
          import java.util.Set;
          
          /**
           * @author Vladimir Hajek
           *
           */
          public class PermutationSimple {
              private static final int MAX_NUMBER = 3;
          
              Set<String> results = new HashSet<>(0);
          
              /**
               * 
               */
              public PermutationSimple() {
                  // TODO Auto-generated constructor stub
              }
          
              /**
               * @param availableNumbers
               * @return
               */
              public static List<String> generatePermutations(Set<Integer> availableNumbers) {
                  List<String> permutations = new LinkedList<>();
          
                  for (Integer number : availableNumbers) {
                      Set<Integer> numbers = new HashSet<>(availableNumbers);
                      numbers.remove(number);
          
                      if (!numbers.isEmpty()) {
                          List<String> childPermutations = generatePermutations(numbers);
                          for (String childPermutation : childPermutations) {
                              String permutation = number + childPermutation;
                              permutations.add(permutation);
                          }
                      } else {
                          permutations.add(number.toString());
                      }
                  }
          
                  return permutations;
              }
          
              /**
               * @param args
               */
              public static void main(String[] args) {
                  Set<Integer> availableNumbers = new HashSet<>(0);
          
                  for (int i = 1; i <= MAX_NUMBER; i++) {
                      availableNumbers.add(i);
                  }
          
                  List<String> permutations = generatePermutations(availableNumbers);
                  for (String permutation : permutations) {
                      System.out.println(permutation);
                  }
          
              }
          }
          

          我认为,这是一个很好的解决方案。

          【讨论】:

            【解决方案9】:

            简单有用的排列索引知识

            创建一个生成正确排列的方法,给定一个介于 {0 和 N! 之间的索引值! -1} 表示“零索引”或 {1 and N!} 表示“一个索引”。

            创建包含“for 循环”的第二个方法,其中下限为 1,上限为 N!。例如.. "for (i; i

            【讨论】:

              【解决方案10】:
              def find(alphabet, alpha_current, str, str_current, max_length, acc):
                
                if (str_current == max_length):
                  acc.append(''.join(str))
                  return
                
                for i in range(alpha_current, len(alphabet)):
                  str[str_current] = alphabet[i]
                  
                  alphabet[i], alphabet[alpha_current] = alphabet[alpha_current], alphabet[i]
                  
                  find(alphabet, alpha_current+1, str, str_current+1, max_length, acc)
                  
                  alphabet[i], alphabet[alpha_current] = alphabet[alpha_current], alphabet[i]
                
                return
              
              max_length = 4
              str = [' ' for i in range(max_length)]
              acc = list()
              find(list('absdef'), 0, str, 0, max_length, acc)
              
              for i in range(len(acc)):
                print(acc[i])
              
              print(len(acc))
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2015-08-27
                • 2010-10-31
                • 2016-02-03
                • 2014-03-15
                • 1970-01-01
                • 2012-02-04
                相关资源
                最近更新 更多