1. 程式人生 > 實用技巧 >全排列(力扣第46題)

全排列(力扣第46題)

題目:給定一個 沒有重複數字的序列,返回其所有可能的全排列。

示例:

輸入: [1,2,3]
輸出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

分析:

  求給定一組數的全排列,也就是排列組合問題,所以屬於Backtracking(回溯)問題,通過DFS解決,只不過需要注意的是,我們一般使用DFS的時候都會設定一個訪問標記的陣列,用於保證深度遞迴的過程中,某一個元素不會被重複訪問,但是由於現在我們要求的是排列組合問題,所以我們要儘可能的把所有的解求出來,那麼只要一條遞迴路徑中有一個元素不同,那就是不用的遞迴路徑,所以當我們從一個元素遞迴返回的時候,要將此元素對應於訪問標記陣列中的值復位,保證從其他路徑路過此元素時,能夠正常的訪問。

  其實對於一組數來說,假設一共有n個數,那麼這n個數全排列的結果是n!個,其具體的計算結果是 n * (n-1) * ……* 2 * 1 。我們可以將這個計算過程想象成我們使用DFS搜尋時進行搜尋的過程,比如最開始的時候,我們從哪個元素最先開始搜尋,此時一共有n個數未被訪問,那麼就有n種選擇;然後繼續搜尋,那麼還剩n-1個數未被訪問,此時可選擇走的方向就有n-1個選擇;……,以此類推,就是求所有的排列的過程。每到一個元素,進行的下一步走向的選擇,就是通過for迴圈實現,保證所有的可能都要經歷。

程式碼實現:

    private List<List<Integer>> reslist;

    
public List<List<Integer>> permute(int[] nums) { if (nums.length == 0 || nums == null){ return new ArrayList<>(); } int n = nums.length; boolean[] isVisited = new boolean[n]; reslist = new ArrayList<List<Integer>>(); List
<Integer> sortres = new ArrayList<>(); for (int i = 0; i < nums.length; i++) { findAllSort(nums,i,isVisited,sortres); } return reslist; } private void findAllSort(int[] nums, int i, boolean[] isVisited, List<Integer> sortres) { if (isVisited[i]){ return; } isVisited[i] = true; sortres.add(nums[i]); if (sortres.size() == nums.length){ reslist.add(new ArrayList<>(sortres)); isVisited[i] = false; sortres.remove(sortres.size()-1); return; } for (int i1 = 0; i1 < isVisited.length; i1++) { if (!isVisited[i1]){ findAllSort(nums,i1,isVisited,sortres); } } isVisited[i] = false; sortres.remove(sortres.size()-1); }

記住,當遍歷完一條路徑的時候,給此路徑新增到結果列表,需要新建一個list物件,然後將sortres結果傳進去,直接將sortres新增到結果列表中是不行的,因為當我們再一次修改sortlist時,原先存於結果列表的內容也會被修改。

上面是我自己實現的程式碼,然後也參考了cyc2018的程式碼,他的程式碼比我的效能要好一些,但是我倆的做法思想基本是一樣的:

public List<List<Integer>> permute(int[] nums) {
    List<List<Integer>> permutes = new ArrayList<>();
    List<Integer> permuteList = new ArrayList<>();
    boolean[] hasVisited = new boolean[nums.length];
    backtracking(permuteList, permutes, hasVisited, nums);
    return permutes;
}

private void backtracking(List<Integer> permuteList, List<List<Integer>> permutes, boolean[] visited, final int[] nums) {
    if (permuteList.size() == nums.length) {
        permutes.add(new ArrayList<>(permuteList)); // 重新構造一個 List
        return;
    }
    for (int i = 0; i < visited.length; i++) {
        if (visited[i]) {
            continue;
        }
        visited[i] = true;
        permuteList.add(nums[i]);
        backtracking(permuteList, permutes, visited, nums);
        permuteList.remove(permuteList.size() - 1);
        visited[i] = false;
    }
}

參考:cyc2018