排列問題 | Medium | LeetCode#46. Permutations
題目敘述

- 題目難度:
Medium - 題目敘述: 給定一個整數陣列
nums其中不包含重複數字,找到所有數字排列後的可能情況。
輸入: nums = [1,2,3]
輸出: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
輸出結果為輸入陣列中元素的各種排列結果。
解法
一開始的想法
Permutations 其實就是經典的 backtracking 題目,也是典型的樹狀結構,在每一層都先選擇一個數字,並且透過遞迴進入下一層,而一但到達指定層數,就可想辦法 return,退回後原先占用在陣列的數字就可以 pop 出來的。但我按照這個想法時做的時候,起初的結果是有重複數字的,也就是 [1,1,1],[1,1,2] … [3,3,3] 像是這種的,後來才進行了修正。
我的解法
1 | class Solution { |
而修正的方式也就是透過 vector STL 當中的 erase 以及 insert,在迴圈當中,先將數字 push 進要回傳的二維陣列中的第二層陣列。接著透過一個變數 restore 保存push進的值,接著在下一層遞迴之前,先將題目給的陣列中將我們選擇的數字 (numList[i])去掉,否則就會發生重複,一旦到達指定層數後,就代表不會在能夠有新的數字加進第二層陣列中,這也代表這一輪的排列完畢,即可加入最終要回傳的二維陣列中。
一旦有陣列從下一層回退到上一層,這時就要將第二層陣列中原先插入的值 pop 出來,以便挪出空位給之後其他種可能的數字放入,並且還要將剛剛從題目陣列中移除的值,加入回來,剛剛所使用的變數 restore 也就要用在這時候。
最後回傳二維陣列。
執行結果

更好的做法
1 | class Solution { |
透過在函數中添加一個 vector<bool> &used 來去控制在每個迴圈中該值是否有使用過,就不用持續對陣列進行移除跟插入的動作了。
複雜度
時間複雜度
- 排列的數量: 全排列的總數是 $n!$,其中
n是nums的長度。 - 遞迴操作: 在每次遞迴調用中,程式會檢查哪些數字尚未被使用(即
!used[i]),這個操作的時間是 $O(n)$。在每個遞迴層,會依次處理所有剩下的數字,這是一個 $O(n)$ 的操作。
總體來說,程式會進行 n! 次排列生成,而每次生成的時間是 O(n),因此時間複雜度為:$O(n \times n!)$
空間複雜度
- 遞迴深度: $O(n)$
- 結果保存在
final_result中,總共有 $n!$ 個排列,每個排列的長度是n。因此結果的空間複雜度是 $O(n \times n!)$
本部落格所有文章除特別聲明外,均採用CC BY-NC-SA 4.0 授權協議。轉載請註明來源 Kevin Liu's 部落格 || Technical || Travel!
評論










