[分析] 同Permutation一题的区别在于输入数组可能包含重复元素,在面试时即使面试官没有明确指出也该想到。如何处理重复元素不致得到重复结果呢?基本思路是排序然后跳过重复元素。Method1 每次循环递归都要排序且要复制一次数组,时间和空间消耗都比较大,Method2是Code Ganker大神的思路,使用一个额外数组used表示元素是否已经被排好位置。去重的关键是for循环一开始的if判断,理解起来有些费劲,大神的解释:只对第一个未被使用的进行递归,如果第一个重复元素前面的元素还没在当前结果中,那么我们不需要进行递归,这一次结果会出现在第一个的递归函数结果中。举例理解下:假设元素 a 有重复, 下标 i 和 i-1 处均是 a, 处理 i 下标时发现 i-1 下标的 a 还未被使用,这种情况下 i 应当跳过,因为循环是从前往后的推进的,i-1 已先被循环处理过,在这层递归中假设元素将排在位置 k 处,则若不跳过 i ,i 也被放在位置 k 处,最终将导致结果重复。
[ref] Code Ganker大神博客
http://blog.csdn.net/linhuanmars/article/details/21570835
public class Solution { public List<List<Integer>> permuteUnique2(int[] nums) { List<List<Integer>> result = new ArrayList<List<Integer>>(); if (nums == null || nums.length == 0) return result; Arrays.sort(nums); recur(nums, new boolean[nums.length], new ArrayList<Integer>(), result); return result; } public void recur(int[] nums, boolean[] used, List<Integer> item, List<List<Integer>> result) { if (item.size() == nums.length) { result.add(new ArrayList<Integer>(item)); return; } for (int i = 0; i < nums.length; i++) { if (i > 0 && !used[i - 1] && nums[i] == nums[i - 1]) continue; if (!used[i]) { item.add(nums[i]); used[i] = true; recur(nums, used, item, result); used[i] = false; item.remove(item.size() - 1); } } } public List<List<Integer>> permuteUnique(int[] num) { List<List<Integer>> result = new ArrayList<List<Integer>>(); if(num == null || num.length == 0) return result; Arrays.sort(num); return permutate(num, 0); } private List<List<Integer>> permutate(int[] num, int beg){ List<List<Integer>> result = new ArrayList<List<Integer>>(); if(beg == num.length - 1){ List<Integer> item = new ArrayList<Integer>(); item.add(num[beg]); result.add(item); return result; } int origin = num[beg]; for(int i = beg; i < num.length; i++){ if(i != beg && num[i] == num[i - 1]) continue; num[beg] = num[i]; num[i] = origin; int[] sub = Arrays.copyOf(num, num.length); Arrays.sort(sub, beg + 1, num.length); for(List<Integer> item : permutate(sub, beg + 1)){ item.add(0, num[beg]); result.add(item); } num[i] = num[beg]; num[beg] = origin; } return result; } }