题目原文:
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
题目大意:
接Middle-题目24,这回数组元素允许重复,还是求所有可能的排列情况。
题目分析:
方法一:(很慢的朴素解法)首先构造一个hashMap,统计每个元素出现的次数,然后开始回溯,先统计这个元素在hashMap中还剩多少个,记为times,然后分别加入1个,2个……再向下搜索,直到hashmap为空则找到一个解。
方法二:discuss中的一个一行解决的办法,暂时不是很能理解。
源码:(language:java/python)
方法一:
public class Solution {
public static List<List<Integer>> permuteUnique(int[] nums) {
HashMap<Integer,Integer> set = new HashMap<Integer,Integer>();
for(int num:nums) {
if(set.containsKey(num))
set.put(num, set.get(num)+1);
else
set.put(num, 1);
}
List<List<Integer>> list = new ArrayList<List<Integer>>();
backtrack(list, new ArrayList<Integer>(), set, 0);
return list;
}
private static void backtrack(List<List<Integer>> list, List<Integer> sublist, HashMap<Integer,Integer> set,int last) {
boolean allZero = true;
for(int value:set.values()) {
if(value!=0) {
allZero = false;
break;
}
}
if(allZero)
list.add(new ArrayList<Integer>(sublist));
for(int key:set.keySet()) {
if(key != last || sublist.size() == 0) {
int times = set.get(key);
for(int j = 1; j <= times; j++) { // count how many keys there are in set,each times add j of them after sublist
set.put(key, times-j);
for(int k = 0; k<j; k++)
sublist.add(key);
backtrack(list, sublist, set, key);
for(int k = 0; k<j; k++)
sublist.remove(sublist.size()-1);
set.put(key, times);
}
}
}
}
}
方法二:
class Solution(object):
def permuteUnique(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
return [[n] + p for n in set(nums) for p in self.permuteUnique(nums[:nums.index(n)] + nums[nums.index(n) + 1:])] or [[]]
成绩:
方法一:19ms,beats 22.52%,众数5ms,19.29%
方法二:136ms,beats 27.77%,众数128ms,15.55%
Cmershen的碎碎念:
解法一原则上回溯过程也是不重不漏的,也没有浪费时间在无效解上,但成绩很差,感觉问题出在了hashmap上,可以考虑其他数据结构(例如数组)。解法二有待深入了解python的语法后慢慢理解。但其实不是一个很快的算法。(而且原则上不推荐这组简短但晦涩的代码)