Permutations II
Question:
Given a list of numbers with duplicate number in it. Find all unique permutations.
Example:
For numbers [1,2,2] the unique permutations are:
[
[1,2,2],
[2,1,2],
[2,2,1]
]
Analysis:
这个问题和subsets很类似,这里要找的是所有排列的情况,同样是用DFS搜索求解。从空集开始,每次往list中加入一个元素,当list的长度和nums的长度一致,就说明找到了一种排列,将其加入result中。重复该过程,直到没有元素可以添加。这里比较tricky的地方是:先添加第一个2和先添加第二个2得到的结果是一样的,所以就产生了重复。为了解决这一问题,引入了visited数组,i是nums中元素的下标,它的作用是记录nums中的元素是否已经被访问过。
举个例子:
nums = [1,2(1),2(2)],括弧中的数字代表第一个2和第二个2。
当程序执行到某一时刻,list = [1, 2(2)],这时与之对应的visited = [true, false, true]。我们发现这时(i = 2),这条判断语句 nums.get(i) == nums.get(i - 1) && !visited[i - 1] 就会返回true,然后跳过该层循环执行下一层。这个判断的意思就是:当访问的当前元素与它前一个元素相等,并且前一个元素还未被访问,换句话说就是先访问的是第二个2,也就是list = [1, 2(2), ..., ...]这种情况。我们可以推测出,在这之前,肯定有一种情况是先访问第一个2的,也就是list = [1, 2(1), ..., ...]。而这两种情况所得出的结果是相等的,所以我们只要continue跳过就行了。
Code:
1 class Solution {
2 /**
3 * @param nums: A list of integers.
4 * @return: A list of unique permutations.
5 */
6 public ArrayList<ArrayList<Integer>> permuteUnique(ArrayList<Integer> nums) {
7 ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
8 ArrayList<Integer> list = new ArrayList<Integer>();
9 if(nums == null || nums.size() == 0) {
10 return result;
11 }
12
13 Collections.sort(nums);
14 boolean[] visited = new boolean[nums.size()];
15 permuteUniqueHelper(result, list, nums, visited);
16 return result;
17 }
18
19 public void permuteUniqueHelper(ArrayList<ArrayList<Integer>> result,
20 ArrayList<Integer> list,
21 ArrayList<Integer> nums,
22 boolean[] visited) {
23 if(list.size() == nums.size()) {
24 result.add(new ArrayList<Integer>(list));
25 }
26
27 for(int i = 0; i < nums.size(); ++i) {
28 if(visited[i] || (i > 0 && nums.get(i) == nums.get(i - 1) && !visited[i - 1]))
29 continue;
30
31 visited[i] = true;
32 list.add(nums.get(i));
33 permuteUniqueHelper(result, list, nums, visited);
34 list.remove(list.size() - 1);
35 visited[i] = false;
36 }
37 }
38 }
Complexity:
时间复杂度是O(n! * n), 因为有n!种情况,每种情况耗时n。空间复杂度是O(n)。