给定一个可包含重复数字的序列nums
,按任意顺序返回所有不重复的全排列。
输入:nums = [1,1,2] 输出: [[1,1,2], [1,2,1], [2,1,1]] 输入:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
这道题目和回溯算法:排列问题
的区别在:给定一个可包含重复数字的序列,要返回所有不重复的全排列。
前面讲解了组合问题
和子集问题
如何去重,其实排列问题也是一样的套路。
注意去重一定要对元素进行排序,这样我们才方便通过相邻的节点来判断是否重复使用了。
一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果。
class Solution { List<Integer> temp = new ArrayList<Integer>(); List<List<Integer>> ans = new ArrayList<List<Integer>>(); public List<List<Integer>> permuteUnique(int[] nums) { boolean[] used = new boolean[nums.length]; Arrays.sort(nums); backtracking(nums,used); return ans; } private void backtracking(int[] nums,boolean[] used) { if(temp.size() == nums.length) { ans.add(new ArrayList<>(temp)); return; } // 遍历可能的搜索起点 for (int i = 0; i < nums.length; i++) { // used[i - 1] == true,说明同一树支nums[i - 1]使用过 // used[i - 1] == false,说明同一树层nums[i - 1]使用过 // 如果同一树层nums[i - 1]使用过则直接跳过 if(i>0 && nums[i]==nums[i-1] && used[i-1] == false){ continue; } if(used[i] == false) { temp.add(nums[i]); used[i] = true; backtracking(nums,used); temp.remove(temp.size()-1); used[i]=false; } } } }