47.全排列II

47.全排列II
文章图片
自己解法 这题解法和全排列类似,只用对同层相同的分支进行剪枝,有点忘了在哪剪了,还是放在后面剪比较好理解,回溯完以后,判断同层有没有相同的。

class Solution {
private List> output = new ArrayList<>();
public List> permuteUnique(int[] nums) {
if (nums.length == 0) {
return output;
}
Arrays.sort(nums);
boolean[] used = new boolean[nums.length];
List res = new ArrayList<>(nums.length);
dfs(nums, used, res, nums.length);
return output;
}
public void dfs(int[] nums, boolean[] used, List res, int n) {
if (res.size() == n) {
output.add(new ArrayList(res));
return;
}
for (int i = 0; i < n; i++) {
if (!used[i]) {
res.add(nums[i]);
used[i] = true;
dfs(nums, used, res, n);
used[i] = false;
res.remove(res.size() - 1);
// 剪枝,减去同层重复的内容
while (i < (n - 1) && nums[i] == nums[i+1]) {
i++;
}
}
}
}
}
官方解法 这种解法是前置剪枝的,首先,当前节点是没有使用过的,不然没意义,然后和前一个节点进行比较,如果和回溯过的前一个点相同,则跳过当前点。
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
public class Solution {
public List> permuteUnique(int[] nums) {
int len = nums.length;
List> res = new ArrayList<>();
if (len == 0) {
return res;
}
// 排序(升序或者降序都可以),排序是剪枝的前提
Arrays.sort(nums);
boolean[] used = new boolean[len];
// 使用 Deque 是 Java 官方 Stack 类的建议
Deque path = new ArrayDeque<>(len);
dfs(nums, len, 0, used, path, res);
return res;
}
private void dfs(int[] nums, int len, int depth, boolean[] used, Deque path, List> res) {
if (depth == len) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < len; ++i) {
if (used[i]) {
continue;
}
// 剪枝条件:i > 0 是为了保证 nums[i - 1] 有意义
// 写 !used[i - 1] 是因为 nums[i - 1] 在深度优先遍历的过程中刚刚被撤销选择
if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
continue;
}
path.addLast(nums[i]);
used[i] = true;
dfs(nums, len, depth + 1, used, path, res);
// 回溯部分的代码,和 dfs 之前的代码是对称的
used[i] = false;
path.removeLast();
}
}
public static void main(String[] args) {
Solution solution = new Solution();
int[] nums = {1, 1, 2};
List> res = solution.permuteUnique(nums);
System.out.println(res);
}
【47.全排列II】}

    推荐阅读