-
实现全排列,但是此题中包含重复元素,并要求结果进行去重复
-
对于给定的数组中包含重复元素,关键是要进行排序Arrays.sort(nums)
-
在回溯函数中,终止条件是,当path的长度和nums的长度相等的时候,将path保存
-
然后进入for循环,首先判断是否重复 i > 0 && nums[i] == nums[i -1] && used[i - 1] == false。含义是当i大于0,出现前后元素相等,并且前一个元素是被释放后(即used值由true变为false),这时说明这个值已经在前面用过,而且被释放。
-
在套用模板之前需要通过if(used[i]) 判断一下当前位置,是否被使用了。避免出现如下情况。添加此判断位置,可以避免重复添加某一位置。
-
二刷:在刚进入for循环的时候,需要判断是否出现了重复的元素,并且上一个元素是否使用过(即被释放了值设置为FALSE),在判断完重复元素之后,还要判断 if(used[i] == false) 即当前的值是否是未使用的,避免重复添加同一个值,此外对数组排序也是关键。
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
boolean[] used = new boolean[nums.length];
Arrays.sort(nums);
if(nums.length == 0) return res;
recur(nums, used);
return res;
}
public void recur(int[] nums, boolean[] used){
//截止条件
if(path.size() == nums.length){
res.add(new ArrayList<>(path));
return;
}
for(int i = 0; i < nums.length; i++){
//当出现重复,并且重复的上一个位置没有被使用过,
//说明前一个元素是被释放后(即used值由true变为false),这时说明这个值已经在前面用过,而且被释放
if(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) continue;
if(used[i] == false){
path.addLast(nums[i]);
used[i] = true;
recur(nums, used);
used[i] = false;
path.removeLast();
}
}
}
}
class Solution {
//定义全局变量
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
boolean[] used;
public List<List<Integer>> permuteUnique(int[] nums) {
if(nums.length == 0){
return res;
}
used = new boolean[nums.length];
//关键:进行排序
Arrays.sort(nums);
recur(nums);
return res;
}
private void recur(int[] nums){
if(path.size() == nums.length){
res.add(new ArrayList<>(path));
return;
}
for(int i = 0; i < nums.length; i++){
if(i > 0 && nums[i] == nums[i -1] && used[i - 1] == false){
continue;
}
//通过判断可以跳过本层上已经检测过的元素,避免重复
if(used[i] == false){
used[i] = true;
path.addLast(nums[i]);
recur(nums);
path.removeLast();
used[i] = false;
}
}
}
}