难度:medium
1、题目介绍
给定一个不含重复数字的数组
nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
2、思路分析
先将组合转换成一种树结构
该题与第 77 的区别 是:该题需要判断节点是否访问过,集合中不允许有重复的元素。如果没有访问过,则标记已访问,防止重复访问 。
举个例子:比如访问 第一个结点 1 时,没有被访问过,进行标记.。继续访问第二个结点2,也没有被访问过,进行标记,当想要访问第三个结点 1 时,已经被访问过了,只能访问 结点3.所以其中的一种组合 [1,2,3] 。
代码:
public class LeetCode_46_backtrack {
//保存最终结果集
private List<List<Integer>> result = new ArrayList<>();
public static void main(String[] args) {
int[] nums = {1, 2, 3};
LeetCode_46_backtrack l = new LeetCode_46_backtrack();
List<List<Integer>> resule = l.permute(nums);
System.out.println(resule);
}
public List<List<Integer>> permute(int[] nums) {
//保存每种组合
List<Integer> com = new ArrayList<>();
//判断结点是否被访问过,true:访问过 false:未访问过
boolean[] flag = new boolean[nums.length];
backtracking(flag, com, nums);
return result;
}
//回溯
public void backtracking(boolean[] flag, List<Integer> com, int[] nums) {
if (com.size() == nums.length) {
//把排列组合增加到最终结果集中
result.add(new ArrayList<>(com));
return;
}
for (int i = 0; i < nums.length; i++) {
//判断 i 这个结点是否访问过。
if (!flag[i]) {
com.add(nums[i]);
flag[i] = true;
backtracking(flag, com, nums);
//以下是回溯操作,在每次回溯时将回溯的元素进行状态重置,以便下一次选择。
flag[i] = false;
com.remove(com.size() - 1);
}
}
}
}
相似题目:第 47 题:全排列 || 难度:medium
题目描述:
给定一个可包含重复数字的序列
nums
,按任意顺序 返回所有不重复的全排列。
该题与上边题的区别就是:不仅要判断当前结点是否访问过,还要判断是否与前一个结点相等,前一个结点是否访问过
思路分析:
还是一样,先把集合转换成一颗树
其实我们可以看到,第二个结点 1 已经在第一次已经访问过了,并且还与前一个结点相等,所以没必要在进行访问了,就算访问最终得到的所有集合都是重复的。
所以我们得知判断重复的条件就是:
i : 代表第 i 个结点。 flag[]:用于判断结点是否被访问过
nums[i] == nums[i-1] && flag[i-1]
一定要提前将数组进行排序,将重复的元素都放在一起,容易判断。
比如:nums[] = {3,3,0,3} 这种情况,最后一个 3 与前一个结点 0,并不相等,但是他与前面俩个都是重复的,所得到的集合也是重复的,所以要先排序。。。。
代码:
public class LeetCode_47_withtrack {
List<List<Integer>> result = new ArrayList<>();
public static void main(String[] args) {
int[] nums = {3,3,0,3};
LeetCode_47_withtrack l = new LeetCode_47_withtrack();
List<List<Integer>> combine = l.permuteUnique(nums);
System.out.println(combine);
}
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums);
List<Integer> com = new ArrayList<>();
boolean[] flag = new boolean[nums.length];
backtracking(flag, com, nums);
return result;
}
public void backtracking(boolean[] flag, List<Integer> com, int[] nums) {
if (nums.length == com.size()) {
result.add(new ArrayList<>(com));
return;
}
for (int i = 0; i < nums.length; i++) {
//增加去重判断,如果当前节点与前一个结点相等并且前面结点访问过,就没有必要继续访问。
if (flag[i] || (i > 0 && !flag[i - 1] && nums[i] == nums[i - 1])) {
continue;
}
com.add(nums[i]);
flag[i] = true;
//进行回溯操作
backtracking(flag, com, nums);
flag[i] = false;
com.remove(com.size() - 1);
}
}
}