【问题标题】:Print out all permutations of an Array [duplicate]打印出数组的所有排列[重复]
【发布时间】:2015-08-03 21:57:31
【问题描述】:

我正在开发一个程序,并且我有一个函数可以交换用户输入的长度数组中的位置。但是,我想弄清楚如何打印出这个函数调用 N!次,这将列出函数中的所有排列。

我的置换函数代码是:

static void nextPerm(int[] A){
    for( int i = (n-1); i > 0; i-- ){
        if( A[i] < A[i+1] ){
            A[i] = pivot;
            continue;
        }
        if( A[i] >= A[i+1] ){
            reverseArray(A);
            return;
        }
    }

    for( int i = n; i > 0; i--){
        if( A[i] > pivot ){
            A[i] = successor;
            continue;
        }
    }

    Swap(pivot, successor);

    int[] B = new int[pivot+1];
    reverseArray(B);

    return;
}

我是否应该在函数 main 中编写一个循环,将其打印出来 n!次?

【问题讨论】:

  • 示例输入:输入数组长度:5
  • 输出:(1, 3, 5, 2, 4) (1, 4, 2, 5, 3) (2, 4, 1, 3, 5) (2, 5, 3, 1, 4) (3, 1, 4, 2, 5) (3, 5, 2, 4, 1) (4, 1, 3, 5, 2) (4, 2, 5, 3, 1) (5 , 2, 4, 1, 3) (5, 3, 1, 4, 2)
  • 这就是这段代码的隐藏含义:int[] B = new int[pivot+1]; reverseArray(B);?这反转了归零的数组,不是吗??? reverseArray(A) - 这看起来也很奇怪......我建议你改用 my answer 的实现,我测试它很好,它按预期工作。

标签: java arrays algorithm permutation factorial


【解决方案1】:

创建(或打印)数组的排列组合递归和迭代比纯粹迭代要容易得多。肯定有迭代的方法可以做到这一点,但结合起来特别简单。具体来说,请注意,根据定义有 N!长度为 N 的数组的排列 - 第一个插槽有 N 个选择,第二个插槽有 N-1 个选择,等等。因此,我们可以将算法分解为两个步骤对于数组中的每个索引 i .

  1. 在子数组arr[i....end] 中选择一个元素作为数组的ith 元素。将该元素与当前位于 arr[i] 的元素交换。
  2. 递归置换arr[i+1...end]

我们注意到这将在 O(N!) 中运行,因为在第一次调用时将进行 N 个子调用,每个子调用将进行 N-1 个子调用,等等。此外,每个元素最终都会被在每个位置,只要只进行交换,就不会复制任何元素。

public static void permute(int[] arr){
    permuteHelper(arr, 0);
}

private static void permuteHelper(int[] arr, int index){
    if(index >= arr.length - 1){ //If we are at the last element - nothing left to permute
        //System.out.println(Arrays.toString(arr));
        //Print the array
        System.out.print("[");
        for(int i = 0; i < arr.length - 1; i++){
            System.out.print(arr[i] + ", ");
        }
        if(arr.length > 0) 
            System.out.print(arr[arr.length - 1]);
        System.out.println("]");
        return;
    }

    for(int i = index; i < arr.length; i++){ //For each index in the sub array arr[index...end]

        //Swap the elements at indices index and i
        int t = arr[index];
        arr[index] = arr[i];
        arr[i] = t;

        //Recurse on the sub array arr[index+1...end]
        permuteHelper(arr, index+1);

        //Swap the elements back
        t = arr[index];
        arr[index] = arr[i];
        arr[i] = t;
    }
}

样本输入、输出:

public static void main(String[] args) {
    permute(new int[]{1,2,3,4});
}

[1, 2, 3, 4]
[1, 2, 4, 3]
[1, 3, 2, 4]
[1, 3, 4, 2]
[1, 4, 3, 2]
[1, 4, 2, 3]
[2, 1, 3, 4]
[2, 1, 4, 3]
[2, 3, 1, 4]
[2, 3, 4, 1]
[2, 4, 3, 1]
[2, 4, 1, 3]
[3, 2, 1, 4]
[3, 2, 4, 1]
[3, 1, 2, 4]
[3, 1, 4, 2]
[3, 4, 1, 2]
[3, 4, 2, 1]
[4, 2, 3, 1]
[4, 2, 1, 3]
[4, 3, 2, 1]
[4, 3, 1, 2]
[4, 1, 3, 2]
[4, 1, 2, 3]

【讨论】:

  • 我试图在不使用包 java.utl.Arrays 的情况下做到这一点
  • 它不使用 util.arrays...
  • 我的函数只能有参数 Int[] A
  • 1) 将 Arrays.toString(..) 替换为手动版本。这实际上是同一件事,只是做出来。 2) 置换函数确实只有一个参数int[] 类型的参数。创建辅助函数是否不受限制?
  • 这是一个了不起的答案!非常感谢
【解决方案2】:

我大部分时间都遵循这种方法..(由 Robert Sedgewick 和 Kevin Wayne 提供。)。

public class Permutations {

    // print N! permutation of the characters of the string s (in order)
    public  static void perm1(String s) { perm1("", s); }
    private static void perm1(String prefix, String s) {
        int N = s.length();
        if (N == 0) System.out.println(prefix);
        else {
            for (int i = 0; i < N; i++)
               perm1(prefix + s.charAt(i), s.substring(0, i) + s.substring(i+1, N));
        }

    }

    // print N! permutation of the elements of array a (not in order)
    public static void perm2(String s) {
       int N = s.length();
       char[] a = new char[N];
       for (int i = 0; i < N; i++)
           a[i] = s.charAt(i);
       perm2(a, N);
    }

    private static void perm2(char[] a, int n) {
        if (n == 1) {
            System.out.println(a);
            return;
        }
        for (int i = 0; i < n; i++) {
            swap(a, i, n-1);
            perm2(a, n-1);
            swap(a, i, n-1);
        }
    }  

    // swap the characters at indices i and j
    private static void swap(char[] a, int i, int j) {
        char c;
        c = a[i]; a[i] = a[j]; a[j] = c;
    }

但是,还有一种更简单的方法可以做到这一点。也许你也可以解决这个问题

class PermutingArray {
    static void permutingArray(java.util.List<Integer> arrayList, int element) {
        for (int i = element; i < arrayList.size(); i++) {
            java.util.Collections.swap(arrayList, i, element);
            permutingArray(arrayList, element + 1);
            java.util.Collections.swap(arrayList, element, i);
        }
        if (element == arrayList.size() - 1) {
            System.out.println(java.util.Arrays.toString(arrayList.toArray()));
        }
    }

    public static void main(String[] args) {
        PermutingArray
                .permutingArray(java.util.Arrays.asList(9, 8, 7, 6, 4), 0);
    }
}

这里的工作示例.. IDeone Link

【讨论】:

  • 第二个解决方案太紧凑了!显示您在 Java API 使用方面的能力。
【解决方案3】:

诀窍是在 nextPerm 是最后一个排列时(即当数组按降序排序时)从 nextPerm 返回一个特殊值(以下代码中的 false):

import java.util.*;

public class Main {
    public static boolean nextPerm(List<Integer> a) {
        int i = a.size() - 2;
        while (i >= 0 && a.get(i) >= a.get(i + 1))
            i--;

        if (i < 0)
            return false;

        int j = a.size() - 1;
        while (a.get(i) >= a.get(j))
            j--;

        Collections.swap(a, i, j);
        Collections.reverse(a.subList(i + 1, a.size()));
        return true;
    }
    ...

然后就可以使用循环了(注意需要的数组一开始是升序排序的):

    ...
    public static void main(String[] args) {
        List<Integer> a = Arrays.asList(new Integer[] {1, 2, 3, 4});
        do {
            System.out.println(a);
        } while (nextPerm(a));
    }
}

你可以在这里试试这个代码:http://ideone.com/URDFsc

【讨论】:

    猜你喜欢
    • 2020-12-26
    • 1970-01-01
    • 1970-01-01
    • 2012-10-11
    • 1970-01-01
    • 2014-05-05
    • 1970-01-01
    • 1970-01-01
    • 2020-12-05
    相关资源
    最近更新 更多