Question
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
给出一个可能包含重复数字的数组,请你返回所有可能的组合(组合不能重复)
Example
[1,1,2] have the following unique permutations:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
Solution
回溯解。这道题和Permutations的区别就是多了重复数字,所以解题方法和subset II差不多,当以第二个重复元素为头时不计算,直接跳过,但是稍有不同的是,我们在Permutations的策略是为已经搜索过的元素进行标记,每次搜索必然会搜索所有元素for(int i = 0; i < nums.length; i++),如果仍然使用之前的i > 0 && nums[i] == nums[i - 1]来判断是否是第二个重复元素为头会导致无法组合,比如{1, 1, 2},当程序遇到第二个1时就会返回,这相当于将输入集合变为了{1,2},因为上面的判断式忽略了一种情况,也就是即使以第一个1为头,这个判断式也成立,所以为了保证是以第二个1为头,我们要保证第一个1没有使用过,也就是isUsed[i - 1] = false
public class Solution { public List<List<Integer>> permuteUnique(int[] nums) { Arrays.sort(nums); // 有重复元素的为了保证不重复统计都需要先排序 List<List<Integer>> res = new ArrayList<>(); backtracking(nums, res, new ArrayList<>(), new boolean[nums.length]); return res; } public void backtracking(int[] nums, List<List<Integer>> res, List<Integer> temp, boolean[] isUsed){ if(temp.size() == nums.length){ res.add(new ArrayList<>(temp)); return; } for(int i = 0; i < nums.length; i++){ // 如果后面的元素和前面的元素相同则不统计,注意这里要加上!isUsed[i - 1],这代表仅当第二个相同元素作为头的情况 // 跳过,比如{1, 1, 2},如果第一个1已经用过代表不是以第二个1作为头的,所以不能continue,而是需要统计,而如果 // 以第二个1作为头,这时候第一个1肯定未被使用,这个时候就不能重复计算,直接跳过 if(i > 0 && nums[i] == nums[i - 1] && !isUsed[i - 1]) continue; if(isUsed[i]) continue; // 这里不能再用temp.contain,因为有重复元素,所以需要标记每个位置是否使用 isUsed[i] = true; temp.add(nums[i]); backtracking(nums, res, temp, isUsed); temp.remove(temp.size() - 1); isUsed[i] = false; } } }