[leetcode]Permutations II
要完成这道题,首先让我们再回顾一下SubSet II http://discuss.leetcode.com/questions/265/subsets-ii
1.每次进入sub的时候,都会记录当前path为一个结果(一个子集);
2.进入sub时,是用i个元素的子集来推导i+1个元素的子集的过程;
3.有了i个元素,第i+1个元素只从原始集合S的位置i之后的元素选;
4.该算法的关键是,有序添加。保证,产生的集合中的元素是有序的。
比如[1,2,3,4,5](暂不考虑重复)
如果进入sub的时候是[1,3],那么下一步是[1,3,4]和[1,3,5]
为什么没有[1,3,2]呢,因为[1,2]比如在[1,3]之前处理过了,它会处理到[1,2,3]的;
5.因为有序,那么已取的i个元素的集合中的最后一个元素,是一个分界。可以用它来判重。
http://www.cnblogs.com/lautsie/p/3249869.html
但对Permutation来说,本来就是尝试不同的顺序,没有有序这个概念,怎么弄呢?
答案是,递归时采用完全不同的方法。(上面这个方法,可能主要对求子集适用。)但在关键的判重部分,对重复的元素采用有序的思想。
例如:
输入为1 1 2,只要保证最后生成的组合中第二个1依旧在第一个1之后,就能保证不会出现重复的组合。
1 1 2,标记为1(1) 1(2) 2,它们能生成的所有组合
去掉1(2)在1(1)之前的情况:
1(1) 1(2) 2
1(1) 2 1(2)
2 1(1) 1(2)
即为所求。
方法采用的是:http://www.cnblogs.com/remlostime/archive/2012/11/13/2768816.html
先对数组进行排序,这样在DFS的时候,可以先判断前面的一个数是否和自己相等,相等的时候则前面的数必须使用了,自己才能使用,这样就不会产生重复的排列了。
最后,莫忘一开始排个序。还有将tmp添加到result里时要new一份,否则后面会被清空。
public class Solution { ArrayList<ArrayList<Integer>> ans = new ArrayList<ArrayList<Integer>>(); ArrayList<Integer> tmp = new ArrayList<Integer>(); public ArrayList<ArrayList<Integer>> permuteUnique(int[] num) { ans.clear(); tmp.clear(); Arrays.sort(num); int len = num.length; boolean[] canUse = new boolean[len]; for (int i = 0; i < len; i++) { canUse[i] = true; } sub(num, canUse); return ans; } private void sub(int[] num, boolean[] canUse) { if (tmp.size() == num.length) { ans.add(new ArrayList<Integer>(tmp)); } else { for (int i = 0; i < num.length; i++) { if (canUse[i]) { if (i!=0 && num[i] == num[i-1] && canUse[i-1]) continue; tmp.add(num[i]); canUse[i] = false; sub(num, canUse); tmp.remove(tmp.size()-1); canUse[i] = true; } } } } }