46.Permutations

題目連接:https://leetcode.com/problems/permutations/description/html

題目大意:給出一串數組進行全排列(數組中數字惟一)。java

法一:模板全排列代碼標記數組版。代碼以下(耗時5ms):數組

 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             list.add(new ArrayList<Integer>(tmp));//這裏必定要用new以後再加入到list中,不然list集合會是空值
13             return;
14         }
15         for(int i =0 ; i < nums.length; i++) {
16             if(vis[i] == 0) {
17                 vis[i] = 1;
18                 tmp.add(nums[i]);
19                 dfs(list, nums, vis, tmp);
20                 tmp.remove(tmp.size() - 1);//刪除最後一個元素
21                 vis[i] = 0;
22             }
23         }
24     }
View Code

另外一種實現方式:模板java版,利用list屬性來進行if條件判斷,省去vis標記數組。代碼以下(耗時26ms):ide

 1     public List<List<Integer>> permute(int[] nums) {
 2         List<List<Integer>> list = new ArrayList<List<Integer>>();
 3         List<Integer> tmp = new ArrayList<Integer>();
 4         dfs(list, nums, tmp);
 5         return list;
 6     }
 7     public static void dfs(List<List<Integer>> list , int[] nums, List<Integer> tmp) {
 8     //    System.out.println(tmp);
 9         if(tmp.size() == nums.length) {
10             if(!list.contains(tmp))
11                 list.add(new ArrayList<Integer>(tmp));//這裏必定要用new以後再加入到list中,不然list集合會是空值
12             return;
13         }
14         for(int i =0 ; i < nums.length; i++) {
15             if(!tmp.contains(nums[i])) {
16                 tmp.add(nums[i]);
17                 dfs(list, nums, tmp);
18                 tmp.remove(tmp.size() - 1);//刪除最後一個元素
19             }
20         }
21     }
View Code

當序列是{1,2,3}時運行結果以下:函數

[]
[1]
[1, 2]--->由於這裏有if條件判斷是否已經選1,因此這裏不會再將第二個1加入到序列當中,而是跳過if條件直接執行i++操做,在第77題組合數中,這裏的i不是從0開始,而是每次dfs時,傳入一個起始下標,這樣就能夠不用if條件判斷起始下標前面的數值是否已經存在,由於確定不會重複選擇。在排列中,不能用傳入起始下標的辦法,由於有可能當前要選的數的下標是在起始下標以前的,若是用起始下標的話,前面的數就無法選到。
[1, 2, 3]--->兩次跳過if條件,執行i++
[1, 3]--->return執行remove,這裏remove的是2,不是3,由於return回來的時候第三個數起始尚未加進去
[1, 3, 2]--->兩次跳過if條件,執行i++
[2]--->return執行remove,這裏remove的是1,緣由同上
[2, 1]
[2, 1, 3]
[2, 3]
[2, 3, 1]
[3]
[3, 1]
[3, 1, 2]
[3, 2]
[3, 2, 1]
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

 

法二(借鑑):非遞歸,假設咱們有了當前前 i 個元素的組合,當第 i+1個元素加入時,咱們須要作的是將這個元素加入以前的每個結果,而且放在每一個結果的每一個位置,由於以前的結果沒有重複,因此加入新元素的結果也不會有重複,好比當前i個元素組合是1,當加入第2個元素的時候,能夠選擇加在1以前,也能夠選擇加在1以後,這樣就能夠獲得兩個不一樣序列,依次類推。代碼以下(耗時7ms):post

 1 public List<List<Integer>> permute(int[] nums) {
 2         LinkedList<List<Integer>> res = new LinkedList<List<Integer>>();//這裏利用LinkedList,而不用ArrayList,由於這樣能夠利用LinkedList.add(i,n)在第i位加入數值
 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                     res.add(resIn);//這裏由於每從結果集中取出一個序列就是清空一個序列,因此這裏add的時候就是一個全新的序列
11                 }
12             }
13         }
14         return res;
15     }
View Code

當數組是{1,2,3}時,運行結果以下:spa

[1]
第一次取到{1}
[2, 1]
[1, 2]
第二次取到{2,1}
[3, 2, 1]
[2, 3, 1]
[2, 1, 3]
第三次取到{1,2}
[3, 1, 2]
[1, 3, 2]
[1, 2, 3]
[[3, 2, 1], [2, 3, 1], [2, 1, 3], [3, 1, 2], [1, 3, 2], [1, 2, 3]]

 法三:由31題http://www.cnblogs.com/cing/p/8001308.html,求解下一個排列所引起的這題的題解,也就是C++裏STL所封裝的nextPermutation函數用java實現後,其餘的代碼跟C++調用相似。注意在求解排列以前,數組要先升序排序,由於nextPermutation的false結果就是在數組是降序時結束。不然會致使求出的全排列不徹底。代碼以下(耗時6ms):code

 1     public List<List<Integer>> permute(int[] nums) {
 2         List<List<Integer>> res = new ArrayList<List<Integer>>();
 3         Arrays.sort(nums);
 4         do {
 5             ArrayList<Integer> listIn = new ArrayList<Integer>();
 6             for(int i = 0; i < nums.length; i++) {
 7                 listIn.add(nums[i]);
 8             }
 9             //每求出一個全排列就加入res結果集中
10             //由下面的嘗試得知,必需要new一個新的,緣由不是新開闢了一個地址空間,而是爲了讓原地址空間不被垃圾回收器回收,而致使原數據沒法讀取的狀況
11             //listIn和a的地址空間相同
12 /*            System.out.println(listIn.hashCode());
13             List<Integer> a = new ArrayList<Integer>(listIn);
14             System.out.println(a.hashCode());
15             res.add(a);*/
16             res.add(new ArrayList<Integer>(listIn));
17         } while(nextPermutation(nums) == true);
18         return res;
19     }
20     public static boolean nextPermutation(int[] nums) {
21         int length = nums.length;
22         int pre = 0, post = 0;//pre標記前面的第一個小數,即nums[pre]<nums[pre+1],post標記後面的第一個大數,即nums[post]>nums[pre]
23         boolean mark = false;//標記是不是降序序列
24         //從後往前找,找到第一個前面的數小於後面的數的下標
25         for(int i = length - 1; i > 0; i--) {
26             if(nums[i - 1] < nums[i]) {
27                 mark = true;
28                 pre = i - 1;
29                 break;
30             }
31         }
32         //從後往前找,找到第一個比前面標記的數大的數的下標
33         for(int i = length - 1; i > 0; i--) {
34             if(nums[i] > nums[pre]) {
35                 post = i;
36                 break;
37             }
38         }
39         int mid = (length - pre - 1) / 2;
40         //若是直接是降序,直接反轉便可
41         if(mark == false) {
42             return false;
43         }
44         int tmp = nums[pre];
45         nums[pre] = nums[post];
46         nums[post] = tmp;
47         //反轉後面的降序序列爲升序序列
48         for(int i = pre + 1; i <= (pre + mid); i++) {
49             int t = nums[i];
50             nums[i] = nums[--length];
51             nums[length] = t;
52         }
53         return true;
54     }
View Code
相關文章
相關標籤/搜索