题目:力扣https://leetcode-cn.com/problems/permutations-ii/
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
int len = nums.length;
int depth = 0;
Deque<Integer> path = new ArrayDeque<>();
boolean[] used = new boolean[len];
List<List<Integer>> ans = new ArrayList<List<Integer>>();
Arrays.sort(nums);
dfs(nums,len,depth,path,used,ans);
return ans;
}
private void dfs(int[] nums,int len,int depth,Deque<Integer> path,boolean[] used,List<List<Integer>> ans){
if(depth==len){
ans.add(new ArrayList(path));
return;
}
for(int i=0;i<len;i++){
if(used[i]){
continue;
}
if(i<len-1 && nums[i]==nums[i+1] && !used[i+1]){
continue;
}
path.addLast(nums[i]);
used[i] = true;
dfs(nums,len,depth+1,path,used,ans);
path.removeLast();
used[i] = false;
}
}
}
思路:这题是leetcode46.全排列的晋级版,但其实这两道题相差并不多。这题仅仅比leetcode46.全排列增加了一个剪枝条件,其余的完全一样。简单叙述一下思路:仍然是深度优先遍历,有两个剪枝的条件:(1)用过的值不可用(2)重复的值不可用。先对nums[]数组排序,排序时剪枝前必须完成的步骤,否则后续剪枝将变得很困难。故技重施递归到最后一层则得到一个解,在回溯的同时需要重置状态然后继续下一轮调用。直至执行完该方法后,返回ans。(详情请见leetcode46.全排列)
1.声明需要用到的变量。与leetcode46.全排列不同的是,这题多了一步给nums[]数组排序的步骤,这一步排序是便于后续剪枝操作而作的准备。
int len = nums.length;
int depth = 0;
Deque<Integer> path = new ArrayDeque<>();
boolean[] used = new boolean[len];
List<List<Integer>> ans = new ArrayList<List<Integer>>();
Arrays.sort(nums);
2.深度优先的递归方法,对的,故技重施。唯一不同的地方是,多了一个if(i<len-1 && nums[i]==nums[i+1] && !used[i+1])的剪枝条件。这个剪枝是避免重复出现,因此,若当前位置的元素与后续元素相同,则跳过当前元素的使用,直接到下一个元素从而避免使用了值相同的元素而导致最后的解出现重复。
private void dfs(int[] nums,int len,int depth,Deque<Integer> path,boolean[] used,List<List<Integer>> ans){
if(depth==len){
ans.add(new ArrayList(path));
return;
}
for(int i=0;i<len;i++){
if(used[i]){
continue;
}
if(i<len-1 && nums[i]==nums[i+1] && !used[i+1]){
continue;
}
path.addLast(nums[i]);
used[i] = true;
dfs(nums,len,depth+1,path,used,ans);
path.removeLast();
used[i] = false;
}
}
3.搞定之后,在主方法调用dfs,返回ans。
dfs(nums,len,depth,path,used,ans);
return ans;