全排列II力扣--47
目录
题目
思路
代码
题目
给定一个可包含重复数字的序列 nums
,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2] 输出: [[1,1,2], [1,2,1], [2,1,1]]
示例 2:
输入:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
思路
去重一定要对元素进行排序,这样我们才方便通过相邻的节点来判断是否重复使用了。
一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果。
对于排列问题,树层上去重和树枝上去重,都是可以的,但是树层上去重效率更高!
这么说是不是有点抽象?
来来来,我就用输入: [1,1,1] 来举一个例子。
树层上去重(used[i - 1] == false),的树形结构如下:
树枝上去重(used[i - 1] == true)的树型结构如下:
大家应该很清晰的看到,树层上对前一位去重非常彻底,效率很高,树枝上对前一位去重虽然最后可以得到答案,但是做了很多无用搜索。
那如果都可以,直接去掉哪个条件可以吗?
不可以!得一直是 true 或者一直是false 才可以,而不是 一会是true 一会又是false
代码
class Solution {
List<List<Integer>> result=new ArrayList<>();
LinkedList<Integer> path=new LinkedList<>();
boolean[] used;//用来标记他使用过没有
public List<List<Integer>> permuteUnique(int[] nums) {
used=new boolean[nums.length];
Arrays.sort(nums);//先排序,让相同的数字排列在一起
Arrays.fill(used, false);
backTracking(nums,used);
return result;
}
public void backTracking(int[] nums,boolean[] used){
if(path.size()==nums.length){
result.add(new ArrayList<>(path));//叶子节点,收集
}
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.add(nums[i]);
backTracking(nums,used);
path.remove(path.size()-1);//回溯
used[i]=false;
}
}
}
}