所谓排列,就是从n个不同的元素中,任取m(m <= n)个排成一列。例如,从[1, 2, 3]中任取2个元素进行排列,就有以下6种情况:[1, 2], [1, 3], [2, 1], [2, 3],[3, 1], [3, 2]。
我的想法是从一维数组a中任取m个元素进行排列,把结果保存在二维数组result中(简单起见,所有元素均为int型别)。二维数组的列数自然是m,我们需要知道二维数组的行数,也就是从一维数组中任取m个元素的排列数。
首先,我们写一个方法,这个方法返回从n个不同元素中任取m个元素的排列数(记作A(n, m))。假设有m个空,我们要把n个不同的数填进去,那么第1个空有n种不同的填法,之后第2个空有n - 1种不同的填法,最后要填第m个空时,还有n - (m - 1)个数,所以第m个空有n - m + 1种不同的填法,由此可以得到:
A(n, m) = n * (n - 1) * (n - 2) * ... * (n - m + 1)
代码如下:
/**
* 使用填空法计算从n个不同元素中任取m个元素的排列数
* @param n 元素总数,需满足 n > 0
* @param m 要选出做排列的元素数,需满足 0 < m <= n
* @return 从n个不同元素中任取m个元素的排列数
* @throws ArithmeticException if (n <= 0 || m <= 0 || m > n)
*/
public static int numberOfPermutation(int n, int m) {
if (n <= 0 || m <= 0 || m > n) {
throw new ArithmeticException("从n个不同元素中任取m个元素进行排列,"
+ "n, m应满足如下条件:"
+ "n > 0 且 0 < m <= n");
}
int result = 1;
for (int i = n; i > n - m; i--) {
result *= i;
}
return result;
}
然后,我们重载上面那个方法:
/**
* 使用填空法计算数组a中任取m个元素的排列数
* @param a 数组,不能为空
* @param m 要选出做排列的元素数,需满足 0 < m <= a.length
* @return 从n个不同元素中任取m个元素的排列数
* @throws ArithmeticException if (a.length == 0 || m <= 0 || m > a.length)
*/
public static int numberOfPermutation(int[] a, int m) {
if (a.length == 0 || m <= 0 || m > a.length) {
throw new ArithmeticException("从数组a任取m个元素进行排列,"
+ "a, m应满足如下条件:"
+ "a.length > 0 且 0 < m <= a.length");
}
return numberOfPermutation(a.length, m);
}
这个方法接收一个数组,返回的是从中取出m个元素的排列数,
这样存放结果的二维数组就可以这样定义:
int[][] result = new int[numberOfPermutation(a, m)][m];
下面我们来看从[1, 2, 3]中任取2个元素进行排列的过程。
首先,我们从[1, 2, 3]中取出1,把它放入result的第1列,原数组变成了[2, 3]。
从[2, 3]中任取1个元素进行排列,把结果保存在二维数组temp中。只需把2和3分别取出放在temp第1行和第2行的第1列。
之后,把temp追加到result的第2列。
从[2, 3]中任取1个元素的排列有2种,所以我们就得到了result的第1行和第2行。
重复上述过程,即可完成排序。
整个过程中,result的变化简单表示如下:
0 0 -> 1 0 -> 1 2 -> 1 2 -> 1 2 -> 1 2 -> 1 2
0 0 -> 1 0 -> 1 3 -> 1 3 -> 1 3 -> 1 3 -> 1 2
0 0 -> 0 0 -> 0 0 -> 2 0 -> 2 1 -> 2 1 -> 2 1
0 0 -> 0 0 -> 0 0 -> 2 0 -> 2 3 -> 2 3 -> 2 3
0 0 -> 0 0 -> 0 0 -> 0 0 -> 0 0 -> 3 0 -> 3 1
0 0 -> 0 0 -> 0 0 -> 0 0 -> 0 0 -> 3 0 -> 3 2
代码如下:
public static int[][] permutation(int[] a, int m) {
int[][] result = new int[numberOfPermutation(a, m)][m];
// 如果m为1,result只有1列
// 只需把a中元素依次取出,放入result
if (m == 1) {
for (int j = 0; j < a.length; j++) {
result[j][0] = a[j];
}
return result;
}
for (int i = 0; i < a.length; i++) {
// 从a中删除a[i],把剩余元素放入临时数组
// 方法int[] delete(int[] a, int i)删除数组a中下标为i的元素,
// 并产生一个新数组返回,事实上它并没有对数组a做出更改
int[] temp = delete(a, i);
// 计算从temp中任取m - 1个元素的排列数t
int t = numberOfPermutation(temp, m - 1);
// 外层循环每进行1次,都将填充result的第i * t行至第(i + 1) * t行的第1列
for (int j = 0; j < t; j++) {
result[i * t + j][0] = a[i];
}
// 第i * t行至第(i + 1) * t行的剩余列,
// 使用从temp中任取m - 1个元素的排列结果进行填充
// 方法void matrixCopy(int[][] src, int srcRowPoc,
// int srcColPoc, int[][] dest, int destRowPoc, int destColPoc)
// 从二维数组src中第srcRowPoc行第srcColPoc列开始,
// 将剩余元素复制到二维数组dest中,
// dest从第destRowPoc行第destColPoc列开始接收数据
matrixCopy(permutation(temp, m - 1), 0, 0, result, i * t, 1);
}
return result;
}
关于方法
int[] delete(int[] a, int i) 和
void matrixCopy(int[][] src, int srcRowPoc, int srcColPoc, int[][] dest, int destRowPoc, int destColPoc),明天再说,今天已经很晚了。
转载于:https://blog.51cto.com/htgylzhq/797364