目录
- 题目思路
- 回溯法
- 拓展
题目来源
47. 全排列 II
题目思路
这道题目和46.全排列的区别在与给定一个可包含重复数字的序列,要返回所有不重复的全排列。
强调的是去重一定要对元素进行排序,这样我们才方便通过相邻的节点来判断是否重复使用了。
我以示例中的 [1,1,2]为例
图中我们对同一树层,前一位(也就是nums[i-1])如果使用过,那么就进行去重。
一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果。
回溯法
class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
boolean[] used;
public List<List<Integer>> permuteUnique(int[] nums) {
if(nums == null || nums.length < 1){
return result;
}
used = new boolean[nums.length];
Arrays.sort(nums);
backTracking(nums,used);
return result;
}
public void backTracking(int[] nums,boolean[] used){
if(path.size() == nums.length){
result.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]){
continue;
}
used[i] = true;
path.add(nums[i]);
backTracking(nums,used);
used[i] = false;
path.remove(path.size()-1);
}
}
}
拓展
去重最为关键的代码为:
if(i>0&&nums[i] == nums[i-1] && used[i-1]==false){
continue;
}
如果改成 used[i - 1] == true, 也是正确的!,去重代码如下:
if(i>0&&nums[i] == nums[i-1] && used[i-1]==true){
continue;
}
这是为什么呢,就是上面我刚说的,如果要对树层中前一位去重,就用used[i - 1] == false,如果要对树枝前一位去重用used[i - 1] == true。
对于排列问题,树层上去重和树枝上去重,都是可以的,但是树层上去重效率更高!
这么说是不是有点抽象?
来来来,我就用输入: [1,1,1] 来举一个例子。
树层上去重(used[i - 1] == false),的树形结构如下:
树枝上去重(used[i - 1] == true)的树型结构如下:
树层上对前一位去重非常彻底,效率很高,树枝上对前一位去重虽然最后可以得到答案,但是做了很多无用搜索。