47.Permutations II

题目链接:https://leetcode.com/problems/permutations-ii/description/

题目大意:全排列一串数(有重复数字)。

法一:也即是46题的法一,只加了一行代码。代码如下(耗时499ms):

 1     public List<List<Integer>> permute(int[] nums) {
 2         List<List<Integer>> list = new ArrayList<List<Integer>>();
 3         int[] vis = new int[nums.length];
 4         Arrays.fill(vis, 0);//初始化全为0
 5         List<Integer> tmp = new ArrayList<Integer>();
 6         dfs(list, nums, vis, tmp);
 7         return list;
 8     }
 9     public static void dfs(List<List<Integer>> list , int[] nums, int[] vis, List<Integer> tmp) {
10     //    System.out.println(tmp);
11         if(tmp.size() == nums.length) {
12             if(!list.contains(tmp))
13                 list.add(new ArrayList<Integer>(tmp));//这里一定要用new之后再加入到list中,否则list集合会是空值
14             return;
15         }
16         for(int i =0 ; i < nums.length; i++) {
17             if(vis[i] == 0) {
18                 vis[i] = 1;
19                 tmp.add(nums[i]);
20                 dfs(list, nums, vis, tmp);
21                 tmp.remove(tmp.size() - 1);//删除最后一个元素
22                 vis[i] = 0;
23             }
24         }
25     }
View Code

法二:也就是46题的法二,只加了一行代码,利用List特性判重:list.contains()。代码如下(耗时78ms):

 1     public List<List<Integer>> permute(int[] nums) {
 2         LinkedList<List<Integer>> res = new LinkedList<List<Integer>>();
 3         res.add(new ArrayList<Integer>());//加一个空的list进去,以保证下面size在第一次的时候就为1,从而保证后面的计算
 4         for(int n : nums) {//遍历nums数组值
 5             for(int size = res.size(); size > 0; size--) {//查看结果集res中已经包含几个序列
 6                 List<Integer> tmp = res.pollFirst();//取出结果集res中的每个序列
 7                 for(int i = 0; i <= tmp.size(); i++) {//对于取出的序列,在每一个位置都尝试加入当前nums数组值,这里的i表示当前取出序列的第i位,比如取出的序列是1,接下来就要在1之前及1之后加入2
 8                     List<Integer> resIn = new ArrayList<Integer>(tmp);//每一个位置都新初始化刚取出的序列,这样保证能在原始取出序列的基础上增添数值
 9                     resIn.add(i, n);//在第i位加入数值n
10                 //    System.out.println(resIn);
11                     if(res.contains(resIn)) continue;
12                     res.add(resIn);//这里因为每从结果集中取出一个序列就是清空一个序列,所以这里add的时候就是一个全新的序列
13                 }
14             }
15         }
16         return res;
17     }
View Code

 剪枝:前面的都是把所有的排列都计算完之后再考虑是否加入结果集中,而下面这个是在计算排列的时候就进行剪枝。这里剪枝利用前后元素的相等性来判断剪枝。正确的剪枝真的可以减少好多的时间复杂度。具体如下(耗时9ms):

 1     public List<List<Integer>> permuteUnique(int[] nums) {
 2         List<List<Integer>> list = new ArrayList<List<Integer>>();
 3         int[] vis = new int[nums.length];
 4         Arrays.fill(vis, 0);//初始化全为0
 5         List<Integer> tmp = new ArrayList<Integer>();
 6         Arrays.sort(nums);//一定要先排序,这样才能保证下面剪枝的时候,相同的元素相邻
 7         dfs(list, nums, vis, tmp);
 8         return list;
 9     }
10     public static void dfs(List<List<Integer>> list , int[] nums, int[] vis, List<Integer> tmp) {
11     //    System.out.println(tmp);
12         if(tmp.size() == nums.length) {
13             list.add(new ArrayList<Integer>(tmp));//这里一定要用new之后再加入到list中,否则list集合会是空值
14             return;
15         }
16         for(int i =0 ; i < nums.length; i++) {
17             //套路剪枝,去除重复元素
18             //选取下一个元素的时候,要查看这个元素的前一个元素是否和它相同,如果相同而且没有使用过,就不用选取这个元素,因为如果选取了这个元素,所得的结果被包含于选取了前一个相同元素的结果中。
19             if(i > 0 && vis[i - 1] == 0 && nums[i - 1] == nums[i]) {
20                 continue;
21             }
22             else if(vis[i] == 0){
23                 vis[i] = 1;
24                 tmp.add(nums[i]);
25                 dfs(list, nums, vis, tmp);
26                 tmp.remove(tmp.size() - 1);//删除最后一个元素
27                 vis[i] = 0;
28             }
29         }
30     }
View Code
原文地址:https://www.cnblogs.com/cing/p/7857798.html