Given a collection of numbers, nums
, that might contain duplicates, return all possible unique permutations in any order.
Example 1:
Input: nums = [1,1,2]
Output:
[[1,1,2],
[1,2,1],
[2,1,1]]
Example 2:
Input: nums = [1,2,3]
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
Constraints:
1 <= nums.length <= 8
-10 <= nums[i] <= 10
解法:
这道题与46题的唯一区别就是给出的数组里有重复的数字,这样一来如果还按照上一题的解法去做,那么肯定会生成出重复的排列。
其实我们可以换一个思路去解决全排列生成问题。比如有数组[1,1,2],那么可以把这三个数字的全排列想象成是一个具有三个空的slot,然后把[1,1,2]想象成一个装了3个球的袋子(两个红球,一个蓝球),那么寻找这三个数的一个排列的过程就是从袋子中每次取出一个球,然后依次放进这三个空的slot中的过程。那么如果我们随机的从袋子里去取三个球,那么很有可能会凑巧的连续几次都取出同一个颜色的球,那么就会出现生成出重复排列的情况。那么有啥办法能避免这种情况呢?我们可以先把这3个球分成两组,两个红球为一组,一个蓝球为一组,然后每次我们都从其中的一组里取一个球,直到把所有空位填满为止。
public static List<List<Integer>> permuteUnique(int[] num) {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
Map<Integer, Integer> groups = new HashMap<>();
for (int n : num) {
groups.putIfAbsent(n, 0) ;
groups.put(n, groups.get(n) + 1);
}
permutation(num.length, groups, new LinkedList<>(), ans);
return ans;
}
public static void permutation(int maxLen, Map<Integer, Integer> groups, LinkedList<Integer> currList, List<List<Integer>> ans){
if(currList.size() == maxLen) {
ans.add(new ArrayList(currList)) ;
return ;
}
for(Entry<Integer, Integer> entry : groups.entrySet()) {
int num = entry.getKey() ;
int count = entry.getValue() ;
if(count == 0) {
continue ;
}
currList.add(num);
groups.put(num, count - 1) ;
permutation(maxLen, groups, currList, ans);
groups.put(num, count) ;
currList.removeLast() ;
}
}