标签:
Given a list of numbers with duplicate number in it. Find all unique permutations.
For numbers [1,2,2] the unique permutations are:
[
[1,2,2],
[2,1,2],
[2,2,1]
]
Do it without recursion.
SOLUTION 1:
递归recursion:
难点当然是去重,所以其他的就不说了,完全参照subsets理解就可以。
考虑去重时候的想法比较简单,首先要模拟这个递归树,发现什么情况下会重复,什么情况下要跳过这一步(其实就是加速DFS)。
这题:( 1, 2, 2)
[]
/ | \
[1] [2] [2](重复)
/ \ / \ \
[1,2] [1,2] [2,1] [2,2] [2,1](重复)
/ (重复) / \ \
[1,2,2] [2,1,2] [2,2,1] .....(重复)
最后只有三个是可用的,其他的都重复了。
这时候不太好直接看出来,所以引入一个visited,在递归的时候,走过的点标1,没走过就是0。比如最左边分支,visited里面发现以前走过2,那就不走这一步了。再比如最右边分支,走到2就发现以前走过,就直接跳过挣个右侧分支。 在这一层访问过 && 前一个大的分支遍历了一次,并且,这个数跟前一个数重合
程序的表示visited.contains(nums[i])可以用map表示,也可以用数组表示,(visited[i] == 1 && (visited[i - 1] == 0 && nums[i] == nums[i -1]))
程序如下(答案参照九章算法:http://www.jiuzhang.com/solutions/permutations-ii/ 具体请看网页):
public class Solution { public ArrayList<ArrayList<Integer>> permuteUnique(int[] num) { ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>(); if(num == null || num.length == 0) return result; ArrayList<Integer> list = new ArrayList<Integer>(); int[] visited = new int[num.length]; Arrays.sort(num); helper(result, list, visited, num); return result; } public void helper(ArrayList<ArrayList<Integer>> result, ArrayList<Integer> list, int[] visited, int[] num) { if(list.size() == num.length) { result.add(new ArrayList<Integer>(list)); return; } for(int i = 0; i < num.length; i++) { if (visited[i] == 1 || (i != 0 && num[i] == num[i - 1] && visited[i - 1] == 0)){ // 上面的判断其实并不影响最终结果,目的是为了让dfs能更快 /* 上面这一连串判断条件,重点在于要能理解!visited.contains(i-1) 要理解这个,首先要明白i作为数组内的序号,i是唯一的 给出一个排好序的数组,[1,2,2] 第一层递归 第二层递归 第三层递归 [1] [1,2] [1,2,2] 序号:[0] [0,1] [0,1,2] 这种都是OK的,但当第二层递归i扫到的是第二个"2",情况就不一样了 [1] [1,2] [1,2,2] 序号:[0] [0,2] [0,2,1] 所以这边判断的时候!visited.contains(0)就变成了true,不会再继续递归下去,跳出循环 步主要就是为了去除连续重复存在的,很神奇反正 = =|| */ continue; } visited[i] = 1; list.add(num[i]); helper(result, list, visited, num); list.remove(list.size() - 1); visited[i] = 0; } } }
标签:
原文地址:http://www.cnblogs.com/tritritri/p/4919120.html