46. 全排列

中等 數組 回溯

前置題目:78. 子集, 90. 子集 II
相似題目:消滅怪物

思路

現在想要一個數組的所有排列方式,像是[1,2,3]就有六種排列。
最初的數組是一種排列,可以用它去拓展出所有排列方式。
dfs(i)代表當前要嘗試的位置,這個位置需要嘗試自己位置之後,所有可能的數字,


  • dfs(0),此時三個數字[1,2,3]都沒選過,第一個位置可以更換為[1,2,3]任意一個數字。假設選2。這時數組變成[2,1,3],再去呼叫dfs(1)
  • dfs(1)這時能選的數字剩兩個,[1,3],在裡面選一個,假設選[3],數組[2,3,1],呼叫dfs(2)
  • dfs(2)只能選一個數字,數組[2,3,1],呼叫dfs(3),終止條件。

在這個過程中,呼叫dfs(i),還沒被選中的數字就是i位置以後的數字,並且在選完之後,要將現場還原,否則對於上一層而言,「還沒被選中的數字」會亂掉。

  • 當我在狀態 A 時要做出多個操作,就需要確保每次操作時,我的狀態都沒有變化。
    • 我操作時,將狀態 A 改成 B 後呼叫遞迴,遞迴結束就應該依舊是狀態 A,所以最後再改回狀態 A。
    • 再次操作,將狀態 A 改成 C 後呼叫遞迴,遞迴結束後應該依舊是狀態 C,所以最後再改回狀態 C。
    • 操作完畢,終止時應該也要是狀態 A。

關於為什麼要還原,看影片會清楚非常多。www.bilibili.com

程式碼

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        int n = nums.size();
        vector<vector<int>> res;
        auto dfs = [&](this auto&& dfs, int i) -> void {
            if(i == n) {
                res.push_back(nums);
            }
            else {
                for(int j = i; j < n; ++j) { // 每次選擇後面的其中一個數字, 跟現在所在的位置交換
                    swap(nums[i], nums[j]);
                    dfs(i + 1);
                    swap(nums[i], nums[j]); // 還原現場
                }
            }
        };
        dfs(0);
        return res;
    }
};

複雜度分析

  • 時間複雜度:O(n×n!)O(n\times{n!})
  • 空間複雜度:O(n)O(n)

顯示設定

背景線條
顯示背景網格線條
懸停發光
滑鼠懸停時顯示霓虹效果
聚光燈
跟隨滑鼠的聚光燈效果
背景透明度
開啟透明玻璃效果
主題顏色
自訂主要顏色