1 题目
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutations-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2 Java
2.1 方法一(回溯递归;HashSet去重)
class Solution {
HashSet<List<Integer>> setList = new HashSet<List<Integer>>();
public List<List<Integer>> permuteUnique(int[] nums) {
List<Integer> list = new LinkedList<Integer>();
boolean[] visited = new boolean[nums.length];
helper(nums, list, visited);
// 用到了HashSet转List的技巧
List<List<Integer>> listList = new LinkedList<List<Integer>>(setList);
return listList;
}
public void helper(int[] nums, List<Integer> list, boolean[] visited){
// 结束,记录结果
if(list.size() == nums.length){
setList.add(new LinkedList<Integer>(list));
return;
}
for(int i = 0; i < nums.length; i++){
// 做选择(更新选择列表、路径)
if(visited[i]) continue;
list.add(nums[i]);
visited[i] = true;
// 更下一层
helper(nums, list, visited);
// 撤销选择
list.remove(list.size() - 1);
visited[i] = false;
}
}
}
2.2 方法二(回溯递归;剪枝去重)
比如在第5层递归,即路径XXXX已确定,在确定第5个元素,遍历选择列表,每个元素都可以做第5个元素,但是若有重复元素,则继续深入递归后得到的结果会重复,所以跳过这些重复元素
class Solution {
List<List<Integer>> listList = new LinkedList<List<Integer>>();
public List<List<Integer>> permuteUnique(int[] nums) {
List<Integer> list = new LinkedList<Integer>();
boolean[] visited = new boolean[nums.length];
helper(nums, list, visited);
return listList;
}
public void helper(int[] nums, List<Integer> list, boolean[] visited){
// 结束,记录结果
if(list.size() == nums.length){
listList.add(new LinkedList<Integer>(list));
return;
}
// 剪枝;记录本层中,已做过“头”的元素值,再出现重复值时跳过(再深入得到的结果和之前得到的一样)
HashSet<Integer> set = new HashSet<Integer>();
for(int i = 0; i < nums.length; i++){
// 做选择(更新选择列表、路径)
if(visited[i] || set.contains(nums[i])) continue;
list.add(nums[i]);
set.add(nums[i]);
visited[i] = true;
// 更下一层
helper(nums, list, visited);
// 撤销选择
list.remove(list.size() - 1);
visited[i] = false;
}
}
}