1. 程式人生 > 其它 >2021-7-12 LeetCode

2021-7-12 LeetCode

今天時間留的不咋夠,再加上這類題還不熟悉,只做了一個。

全排列

46. 全排列 - 力扣(LeetCode) (leetcode-cn.com)

給定一個不含重複數字的陣列 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,還節約了時間。