題目連接:https://leetcode.com/problems/permutations-ii/description/數組
題目大意:全排列一串數(有重複數字)。ide
法一:也便是46題的法一,只加了一行代碼。代碼以下(耗時499ms):spa
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 }
法二:也就是46題的法二,只加了一行代碼,利用List特性判重:list.contains()。代碼以下(耗時78ms):code
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 }
剪枝:前面的都是把全部的排列都計算完以後再考慮是否加入結果集中,而下面這個是在計算排列的時候就進行剪枝。這裏剪枝利用先後元素的相等性來判斷剪枝。正確的剪枝真的能夠減小好多的時間複雜度。具體以下(耗時9ms):blog
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 }