Java 全排列递归算法
无重复项的全排列
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> lists = new ArrayList<>();
permulation(lists, nums, 0);
return lists;
}
public void permulation(List<List<Integer>> lists, int[] nums, int start) {
if (start == nums.length) { // 当n定位到最后一个数时,即到递归出口
List<Integer> list = new ArrayList<>();
for(int num:nums){
list.add(num);
}
lists.add(list);
return;
}
for (int i = start; i < nums.length; i++) {
swap(nums, start, i); // 交换位置
permulation(lists, nums, start + 1);
swap(nums, start, i); // 恢复原来的顺序,进行下一次交换
}
}
public void swap(int[] nums,int i,int j){
int temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
有重复项的全排列
将这个问题看作有 n 个排列成一行的空格,我们需要从左往右依次填入题目给定的 n 个数,每个数只能使用一次。
那么很直接的可以想到一种穷举的算法,即从左往右每一个位置都依此尝试填入一个数,看能不能填完这 n 个空格,在程序中我们可以用「回溯法」来模拟这个过程。
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
List<Integer> perm = new ArrayList<Integer>();
boolean[] vis = new boolean[nums.length];
Arrays.sort(nums);
backtrack(nums, ans, vis, 0, perm);
return ans;
}
public void backtrack(int[] nums, List<List<Integer>> ans, boolean[] vis, int idx, List<Integer> perm) {
if (idx == nums.length) {
ans.add(new ArrayList<Integer>(perm));
return;
}
for (int i = 0; i < nums.length; ++i) {
// 对原数组排序,保证相同的数字都相邻,然后每次填入的数一定是这个数所在重复数集合中「从左往右第一个未被填过的数字」,即如下的判断条件:
if (vis[i] || (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1])) {
continue;
}
perm.add(nums[i]);
vis[i] = true;
backtrack(nums, ans, vis, idx + 1, perm);
vis[i] = false;
perm.remove(idx);
}
}
相关文章