2021-7-12 LeetCode
阿新 • • 發佈:2021-07-20
今天時間留的不咋夠,再加上這類題還不熟悉,只做了一個。
全排列
給定一個不含重複數字的陣列 nums
,返回其 所有可能的全排列 。你可以 按任意順序*返回答案。
輸入:nums = [1,2,3]
輸出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
思路:
採用遞迴,核心思想如:需要將[1,2,3]全排列,拆分成兩部分,第一個數字和剩下的數字,在這裡,可以拆分為1 和2 3,2 和 1 3,3 和1 2。則[1,2,3]的全排列相當於 1加上[2,3]的全排列,即[2,3],[3,2],最終以1開頭的結果為[1,2,3]和[1,3,2],剩下的數字類似,最終把分別以1,2,3開頭的全排列加起來就是所有排列結果。整體思路就是這樣,能力不足,不太容易用更通俗的語言和原理來解釋,只能通過例子來解釋。
程式碼:
未優化版本:
時間和空間複雜度都很高。。。。
// 交換陣列中兩個數 public void swap(int[] list, int idx1, int idx2) { int tmp = list[idx1]; list[idx1] = list[idx2]; list[idx2] = tmp; } public List<List<Integer>> permute(int[] nums) { if (nums.length == 0) return null; List<List<Integer>> perList = new ArrayList<>(); List<Integer> per = new ArrayList<>(); if (nums.length == 1) { per.add(nums[0]); perList.add(per); return perList; } // 遍歷以每個數字作為首字母的排列 for (int j = 0; j < nums.length; j++) { swap(nums, 0, j); List<List<Integer>> tmp = permute(Arrays.copyOfRange(nums, 1,nums.length)); for (List<Integer> i : tmp) { per = new ArrayList<>(); per.add(nums[0]); per.addAll(i); perList.add(per); } swap(nums, j, 0); } return perList; }
優化版本:
public void backTrace(int first, List<Integer> out, List<List<Integer>> res,int len){ if (first == len) { res.add(new ArrayList<>(out)); return; } for (int i = first; i < len; i++) { Collections.swap(out, i, first); backTrace(first + 1,out, res, len); Collections.swap(out, first, i); } } public List<List<Integer>> permute(int[] nums) { List<List<Integer>> perList = new ArrayList<>(); List<Integer> out = new ArrayList<>(); for (int i : nums) { out.add(i); } backTrace(0, out,perList, nums.length); return perList; }
這是參照題解寫的程式碼(雖然基本上和題解一模一樣了),看了這個程式碼後分析了一下自己前面寫的程式碼存在的問題。 我前面是通過nums來在遞迴過程中生成一個個List<Integer>,再通過addAll方法一個個新增進上一級遞迴的結果中。。。現在看來這樣的方法真的很蠢,浪費了很多空間不說,時間也用了很多。還有就是我之前是通過交換nums裡面的元素再新增進List<Integer>中,其實這完全可以合併成一步:先把nums的全部元素新增進一個List中,然後只需要不斷遞迴交換裡面的元素就行了。這樣就剩下了很多中間產生的List,還節約了時間。