数组的排列

26 浏览
0 Comments

数组的排列

举个例子,我有这个数组:

int a[] = new int[]{3,4,6,2,1};

我需要列出所有的排列,但是如果有一个排列是这样的 {3,2,1,4,6},其他的排列就不能相同。我知道如果数组的长度是n,那么就会有n!种可能的组合。如何编写这个算法呢?

更新:谢谢,但是我需要一个伪代码算法,像这样:

for(int i=0;i

只需要算法。是的,API函数是好的,但是对我帮助不大。

0
0 Comments

Permutation of array(数组的排列)是一个常见的问题,解决这个问题有多种方法。下面是一个用Java实现的排列的示例代码,这个代码可以生成给定数组的所有排列。

// Permute.java -- A class generating all permutations
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.lang.reflect.Array;
public class Permute implements Iterator {
   private final int size;
   private final Object [] elements;  // copy of original 0 .. size-1
   private final Object ar;           // array for output,  0 .. size-1
   private final int [] permutation;  // perm of nums 1..size, perm[0]=0
   private boolean next = true;
   // int[], double[] array won't work :-(
   public Permute (Object [] e) {
      size = e.length;
      elements = new Object [size];    // not suitable for primitives
      System.arraycopy (e, 0, elements, 0, size);
      ar = Array.newInstance (e.getClass().getComponentType(), size);
      System.arraycopy (e, 0, ar, 0, size);
      permutation = new int [size+1];
      for (int i=0; i<size+1; i++) {
         permutation [i]=i;
      }
   }
   private void formNextPermutation () {
      for (int i=0; i<size; i++) {
         // i+1 because perm[0] always = 0
         // perm[]-1 because the numbers 1..size are being permuted
         Array.set (ar, i, elements[permutation[i+1]-1]);
      }
   }
   public boolean hasNext() {
      return next;
   }
   public void remove() throws UnsupportedOperationException {
      throw new UnsupportedOperationException();
   }
   private void swap (final int i, final int j) {
      final int x = permutation[i];
      permutation[i] = permutation [j];
      permutation[j] = x;
   }
   // does not throw NoSuchElement; it wraps around!
   public Object next() throws NoSuchElementException {
      formNextPermutation ();  // copy original elements
      int i = size-1;
      while (permutation[i]>permutation[i+1]) i--;
      if (i==0) {
         next = false;
         for (int j=0; j<size+1; j++) {
            permutation [j]=j;
         }
         return ar;
      }
      int j = size;
      while (permutation[i]>permutation[j]) j--;
      swap (i,j);
      int r = size;
      int s = i+1;
      while (r>s) { swap(r,s); r--; s++; }
      return ar;
   }
   public String toString () {
      final int n = Array.getLength(ar);
      final StringBuffer sb = new StringBuffer ("[");
      for (int j=0; j<n; j++) {
         sb.append (Array.get(ar,j).toString());
         if (j<n-1) sb.append (",");
      }
      sb.append("]");
      return new String (sb);
   }
   public static void main (String [] args) {
      for (Iterator i = new Permute(args); i.hasNext(); ) {
         final String [] a = (String []) i.next();
         System.out.println (i);
      }
   }
}

这段代码实现了一个名为`Permute`的类,该类接受一个对象数组作为参数,并生成该数组的所有排列。它使用了迭代器模式来逐个返回排列。`Permute`类的构造函数接受一个对象数组作为参数,并将其复制到`elements`数组中。它还创建了一个与原始数组类型相同的新数组`ar`,用于存储输出结果。`permutation`数组存储了排列的索引。

在`Permute`类的`next`方法中,首先调用了`formNextPermutation`方法来生成下一个排列。然后使用循环找到当前排列的下一个较大的排列。如果找不到下一个排列,则将`next`标志设置为`false`,并重置`permutation`数组。最后,返回生成的排列。

`Permute`类还提供了`toString`方法,用于将排列转换为字符串表示。`main`方法使用`Permute`类来生成给定数组的所有排列,并将它们打印到控制台。

这个实现使用了Java的反射机制,因此可以处理任意类型的对象数组。然而,它不能处理原始类型的数组。

Permutation of array(数组的排列)是一个常见的问题,这段代码提供了一种解决方法。它通过生成给定数组的所有排列,并使用迭代器模式逐个返回排列。这个实现可以处理任意类型的对象数组。如果需要处理原始类型的数组,需要对代码进行修改。

0
0 Comments

排列数组是一个常见的问题,即将数组中的元素重新排列,以产生所有可能的排列组合。这个问题通常出现在需要枚举所有可能排列的情况下,例如在算法设计中或在解决某些数学问题时。

解决这个问题的一种常见方法是使用C++的标准库函数std::next_permutation。该函数位于<algorithm>头文件中,并且可以在C++中方便地实现排列数组。

下面是一个示例代码,展示了如何使用std::next_permutation函数来排列数组:

int a[] = {3,4,6,2,1};
int size = sizeof(a)/sizeof(a[0]);
std::sort(a, a+size);
do {
  // 打印数组a的元素
} while(std::next_permutation(a, a+size));

在这个示例中,我们首先对数组a进行排序,以确保得到的排列是按照字典顺序的。然后,我们使用do-while循环来重复调用std::next_permutation函数,直到所有可能的排列都被枚举完毕。在每次循环中,我们可以对数组a的元素进行处理,例如打印出来。

总之,通过使用C++的std::next_permutation函数,我们可以方便地解决排列数组的问题,并且能够枚举出所有可能的排列组合。这在算法设计和解决数学问题时非常有用。

0
0 Comments

排列数组(Permutation of array)问题的出现是因为需要打印出一个数组的所有排列。解决方法是使用递归算法,通过交换数组中的元素来生成所有可能的排列。代码如下:

public class Permute{
    static void permute(java.util.List arr, int k){
        for(int i = k; i < arr.size(); i++){
            java.util.Collections.swap(arr, i, k);
            permute(arr, k+1);
            java.util.Collections.swap(arr, k, i);
        }
        if (k == arr.size() -1){
            System.out.println(java.util.Arrays.toString(arr.toArray()));
        }
    }
    public static void main(String[] args){
        Permute.permute(java.util.Arrays.asList(3,4,6,2,1), 0);
    }
}

这个算法的核心思想是,首先将数组的第一个元素和数组中的任意一个元素进行交换,然后递归地对剩下的元素进行排列。在递归调用之后,必须将交换过的元素再次交换回来,以恢复元素的顺序(即进行回溯)。当k等于数组长度减1时,打印出当前的排列。

然而,这个算法存在一些问题。首先,它是递归算法,不太适合与迭代器一起使用。其次,如果输入数组中允许重复元素,则无法得到正确的结果。例如,对于输入[3,3,4,4],期望的所有排列(不重复)应该是:

[3, 3, 4, 4]
[3, 4, 3, 4]
[3, 4, 4, 3]
[4, 3, 3, 4]
[4, 3, 4, 3]
[4, 4, 3, 3]

但是如果直接应用上述的permute函数,会得到[3,3,4,4]四次,这并不是我们期望的结果。这种情况下,正确的排列数是4!/(2!*2!)=6。

为了解决这个问题,可以修改上述算法,但是这样做会显得不够简洁。幸运的是,有一种更好的算法可以解决这个问题。这个算法可以处理重复值,并且不使用递归。核心思想是将任何对象的排列问题转化为整数的排列问题。为了得到一个整数数组的排列,首先将数组按升序排序,然后将其转化为降序排列。为了生成下一个排列,需要找到从末尾开始的第一个索引,该索引处的值不再是降序。然后将该索引处的值改为大于它的最小值,并将其后的部分按升序排列。下面是算法的核心部分:

// ind是一个整数数组
for(int tail = ind.length - 1;tail > 0;tail--){
    if (ind[tail - 1] < ind[tail]){//还在递增
        //找到最后一个不超过ind[tail-1]的元素
        int s = ind.length - 1;
        while(ind[tail-1] >= ind[s])
            s--;
        swap(ind, tail-1, s);
        //将尾部的元素顺序反转
        for(int i = tail, j = ind.length - 1; i < j; i++, j--){
            swap(ind, i, j);
        }
        break;
    }
}

下面是完整的迭代器代码。构造函数接受一个对象数组,并使用HashMap将其映射为整数数组。代码如下:

import java.lang.reflect.Array;
import java.util.*;
class Permutations implements  Iterator{
    private E[] arr;
    private int[] ind;
    private boolean has_next;
    public E[] output;//next()返回这个数组,将其设为public
    Permutations(E[] arr){
        this.arr = arr.clone();
        ind = new int[arr.length];
        //将任何元素的数组转化为整数数组 - 使用第一次出现的索引进行枚举
        Map hm = new HashMap();
        for(int i = 0; i < arr.length; i++){
            Integer n = hm.get(arr[i]);
            if (n == null){
                hm.put(arr[i], i);
                n = i;
            }
            ind[i] = n.intValue();
        }
        Arrays.sort(ind);//从升序开始
        //output = new E[arr.length]; <-- 由于Java中的泛型不能这样做,所以使用反射
        output = (E[]) Array.newInstance(arr.getClass().getComponentType(), arr.length);
        has_next = true;
    }
    public boolean hasNext() {
        return has_next;
    }
    /**
     * 计算下一个排列。每次返回相同的数组实例!
     * 
     */
    public E[] next() {
        if (!has_next)
            throw new NoSuchElementException();
        for(int i = 0; i < ind.length; i++){
            output[i] = arr[ind[i]];
        }
        //获取下一个排列
        has_next = false;
        for(int tail = ind.length - 1;tail > 0;tail--){
            if (ind[tail - 1] < ind[tail]){//还在递增
                //找到最后一个不超过ind[tail-1]的元素
                int s = ind.length - 1;
                while(ind[tail-1] >= ind[s])
                    s--;
                swap(ind, tail-1, s);
                //将尾部的元素顺序反转
                for(int i = tail, j = ind.length - 1; i < j; i++, j--){
                    swap(ind, i, j);
                }
                has_next = true;
                break;
            }
        }
        return output;
    }
    private void swap(int[] arr, int i, int j){
        int t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }
    public void remove() {
    }
}

使用示例代码如下:

Permutations perm = new Permutations(new Integer[]{3,3,4,4,4,5,5});
int count = 0;
while(perm.hasNext()){
    System.out.println(Arrays.toString(perm.next()));
    count++;
}
System.out.println("total: " + count);

以上代码将打印出所有的210个排列。

对于问题中提到的为什么是4!/(2!*2!)=6而不是4!/(2!)=12的疑问,可以这样解释:首先,我知道答案是6(从[3,3,4,4]的例子中可以得到)。然后,我们将[3,3,4,4]想象成两个蓝色球和两个红色球。问题是如何排列这些球(相同颜色的球是一样的)。如果你已经排好了球的位置,那么交换蓝色球(2!种方式)或红色球(2!种方式)不会改变结果。现在,我们有4!种方式来放置4个球,但是交换蓝色球(2!种方式)或红色球(2!种方式)不会改变球的位置。所以最终答案是4!/(2!*2!)。

第一个算法的时间复杂度是O(n*n!),这是我尝试过的最快的排列算法。

0