概述
全排列在很多竞赛题中会经常用到,因为只有枚举出数组中元素的所有可能的组合情况,才能进行题目的下一步操作,那么这篇文章就用递归的思想来实现全排列。
首先我们先举一个最简单的全排列的例子,给出数组{1,2,3},那么这个数组的全排列就有6种情况:
{1,2,3} {1,3,2} {2,1,3} {2,3,1} {3,1,2} {3,2,1}
通过递归可以轻松的实现全排列。
全排列的实现
交换法
import java.util.Arrays;
public class DemoTest {
public static void main(String[] args) {
int[] arr = { 1, 2, 3 };
f(0, arr);
}
//进行全排列
private static void f(int k, int[] arr) {
if (k == arr.length) {
System.out.println(Arrays.toString(arr));
return;
}
for (int i = k; i < arr.length; i++) {
int t=arr[k];
arr[k]=arr[i];
arr[i]=t;
f(k+1,arr);
t=arr[k];
arr[k]=arr[i];
arr[i]=t;
}
}
}
注意:上面这种交换法,在待排元素中如果出现重复元素,那么其全排列结果会出现重复情况,那么此时我们需要采用“选取法”。
选取法
public class Main {
public static int[] arr = {1, 1, 3};//待排元素
public static void main(String[] args) {
dfs2(0);
}
public static int[] path = new int[arr.length];//保存选取元素的集合
public static boolean[] visited = new boolean[arr.length];//对应待排集合中的元素,表示对应元素是否被选过
public static void dfs2(int k) {//进行不重复全排列
if (k == path.length) {
System.out.println(Arrays.toString(path));
return;
}
for (int i = 0; i < arr.length; i++) {
if (i > 0 && arr[i - 1] == arr[i] && !visited[i-1]) {//这个判断是保证不重复的关键,如果当前元素与前面那个元素相同且前面那个元素并没有被选取的情况下,跳过此次循环
continue;
}
if(!visited[i]){
path[k] = arr[i];
visited[i] = true;
dfs2(k + 1);
visited[i] = false;//回溯
}
}
}
}
使用此种方法之前,必须对待排元素进行排序,使得相同元素相邻,才能使用这种全排列方法,不然结果是错的。