题目描述:给定数列 a ,求该数列的全排列(a为数组)
解:
全排列分为两种,带重复元素的和不带重复元素的。
1.不带重复元素的(交换法)
递归的去确定 a 的每个位置
import java.util.Arrays;
public class Main {
static int[] a = {1,5,2};
public static void main(String[] args) {
f(0);
}
//交换法 k:确定a的第k个位置
private static void f(int k) {
if(k == a.length) {//说明整个a确定完了,此时的a就是一种新的排列结果
System.out.println(Arrays.toString(a));
return ;
}
for(int i = k;i < a.length;i++) {//将第 k 位和后面的每一位交换
int tmp = a[i];
a[i] = a[k];
a[k] = tmp;
f(k + 1);
tmp = a[i];//回溯
a[i] = a[k];
a[k] = tmp;
}
}
}
运行结果:
[1, 5, 2]
[1, 2, 5]
[5, 1, 2]
[5, 2, 1]
[2, 5, 1]
[2, 1, 5]
2.带重复元素的(抓取法)
原始数列不动,增加一个容器 path,从原始数列中抓取元素放到 path 中
(抓取法也适用于不带重复元素的)
import java.util.Arrays;
public class Main {
static int[] a = {1,5,5};
static boolean[] visited = new boolean[a.length]; //visited[i]表示a中的第i个元素有没有被抓过
public static void main(String[] args) {
int[] path = new int[a.length];
f(0, path);
}
//确定path的第 k 个位置
private static void f(int k, int[] path) {
if(k == path.length) {//说明整个path确定完了,此时的path就是一种新的排列结果
System.out.println(Arrays.toString(path));
return ;
}
for(int i = 0;i < a.length;i++) {挨个考虑a中的第 i个元素
//准备抓取的第i个元素和上一个元素值相同,且上一个元素没被抓过,那就不能抓第i个元素
if(i > 0 && a[i] == a[i - 1] && !visited[i - 1]) continue;
if(!visited[i]) { //第i个元素没被抓过
visited[i] = true;
path[k] = a[i];//将第i个元素a[i]抓到path中的第k个位置
f(k + 1, path);
visited[i] = false;//回溯
}
}
}
}
运行结果:
[1, 5, 5]
[5, 1, 5]
[5, 5, 1]