回溯day5
作者:互联网
46. 全排列
class Solution {
private List<List<Integer>> res;
private LinkedList<Integer> path;
public List<List<Integer>> permute(int[] nums) {
res = new ArrayList<>();
path = new LinkedList<>();
if (nums.length == 0 || nums == null) return res;
else if (nums.length == 1) {
path.add(nums[0]);
res.add(new ArrayList<>(path));
return res;
}
backtracking(nums);
return res;
}
private void backtracking(int[] nums) {
int len = nums.length;
//最小子问题 排两个
if (len == 2) {
path.add(nums[0]);
path.add(nums[1]);
res.add(new ArrayList<>(path));
path.removeLast();
path.removeLast();
path.add(nums[1]);
path.add(nums[0]);
res.add(new ArrayList<>(path));
path.removeLast();
path.removeLast();
}
for (int i = 0; i < len; i++) {
//不断细化成子问题 直到子数组长度为2就是最小子问题
int[] descendant = new int[len - 1];
int j = 0;
//当前作为头的数不是原数组nums第一个元素 需要将其前面所有元素添加到子需排列数组中
if (i > 0) {
for (; j < i; j++) {
descendant[j] = nums[j];
}
}
//nums下标i以后的数加入子数组。
for (; j < len - 1; j++) {
descendant[j] = nums[j + 1];
}
path.add(nums[i]);
backtracking(descendant);
path.removeLast();
}
}
}
这里是通过new一个子数组descendant排除已排元素,亦可以定义一个used数组存已经用过的数,代码会更加简洁。
class Solution {
private List<List<Integer>> res;
private LinkedList<Integer> path;
private int len;
private boolean used[];
public List<List<Integer>> permute(int[] nums) {
res = new ArrayList<>();
path = new LinkedList<>();
len = nums.length;
used = new boolean[len];
if (len == 0 || nums == null) return res;
backtracking(nums);
return res;
}
private void backtracking(int[] nums) {
if (len == path.size()) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < len; i++) {
//使用used数组判断元素是否被使用过
if (used[i]) continue;
path.add(nums[i]);
used[i] = true;
backtracking(nums);
path.removeLast();
used[i] = false;
}
}
}
47. 全排列 II
class Solution {
private List<List<Integer>> res;
private LinkedList<Integer> path;
private boolean[] used;
private int len;
public List<List<Integer>> permuteUnique(int[] nums) {
res = new ArrayList<>();
len = nums.length;
if (len == 0 || nums == null) return res;
path = new LinkedList<>();
used = new boolean[len];
backtracking(nums);
return res;
}
private void backtracking(int[] nums) {
if (len == path.size()) {
res.add(new ArrayList<>(path));
return;
}
Set<Integer> hashSet = new HashSet<>();
for (int i = 0; i < len; i++) {
//子处理中跳过已使用的数 同层次去重
if (used[i] || hashSet.contains(nums[i])) continue;
hashSet.add(nums[i]);
used[i] = true;
path.add(nums[i]);
backtracking(nums);
path.removeLast();
used[i] = false;
}
}
}
也可以使用used数组去重,i > 0 && nums[i] == nums[i - 1] && used[i-1] == false表示同层树已经使用过(在循环中), used[i-1] == true表示在同一树枝中使用过(在递归中)。
class Solution {
private List<List<Integer>> res;
private LinkedList<Integer> path;
private boolean[] used;
private int len;
public List<List<Integer>> permuteUnique(int[] nums) {
res = new ArrayList<>();
len = nums.length;
if (len == 0 || nums == null) return res;
path = new LinkedList<>();
used = new boolean[len];
Arrays.sort(nums);
backtracking(nums);
return res;
}
private void backtracking(int[] nums) {
if (len == path.size()) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < len; i++) {
//同层次去重 used[i] == false表示,使用i元素在前一个树枝同一层使用过且处理完毕
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
used[i] = false;
continue;
}
//子处理中跳过已使用的数
if (used[i]) continue;
used[i] = true;
path.add(nums[i]);
backtracking(nums);
path.removeLast();
used[i] = false;
}
}
}
标签:used,nums,res,day5,len,回溯,path,new 来源: https://www.cnblogs.com/lizihhh/p/backtracking05.html