在java中生成不带重复/排列的变体

时间:2009-12-14 10:53:56

标签: java algorithm permutation variations

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

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

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

如果有人可以帮我解决这个问题,我会非常感激,特别是提供一些代码和线索。

10 个答案:

答案 0 :(得分:6)

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

至于保持重复免费,我建议采用一种简单的递归方法:对于每个数字,你可以选择将它带入你的变体中,所以你的递归计数通过数字和分叉成两个递归调用,其中一个是包含数字,其中包括数字。然后,在到达最后一个数字后,每个递归基本上为您提供一个(唯一的,排序的)无重复数字列表。然后,您可以创建此列表的所有可能排列,并组合所有这些排列以实现最终结果。

(与duffymo说的相同:我不会为此提供代码)

高级注释:递归基于0/1(排除,包含),可以直接转换为位,因此是整数。因此,为了获得所有可能的数字组合而不实际执行递归本身,您可以简单地使用所有10位整数并迭代它们。然后解释数字,使得设置位对应于包含需要置换的列表中的数字。

答案 1 :(得分:2)

这是我的Java代码。随意询问您是否不理解。这里的要点是:

  
      
  1. 再次排序字符数组。例如:a1 a2 a3 b1 b2 b3 ....(a1 = a2 = a3)
  2.   
  3. 生成排列并始终保持条件:索引a1<指数a2<指数a3 ......
  4.   
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");
    }
}

答案 2 :(得分:2)

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

?

答案 3 :(得分:0)

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

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

例如,

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

...

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

答案 4 :(得分:0)

使用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));
    }
}

答案 5 :(得分:0)

此代码类似于没有重复的代码,添加了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;

}

为我工作

答案 6 :(得分:0)

没有重复的排列是基于定理的,结果量是元素计数的因子(在这种情况下是数字)。在你的情况下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)!

答案 7 :(得分:0)

有一种解决方案不是来自我的,但它非常好而且复杂。

    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);
        }

    }
}

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

答案 8 :(得分:0)

简要有用的排列索引知识

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

创建第二个包含“for循环”的方法,其中下限为1,上限为N!。例如..“for(i; i&lt; = N!; i ++)”对于循环的每个实例调用第一个方法,将i作为参数传递。

答案 9 :(得分:0)

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))