1、題目描述
https://leetcode-cn.com/problems/permutations/
給定一個 沒有重複 數字的序列,返回其所有可能的全排列。
輸入: [1,2,3]
輸出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
2、代碼詳解
進階題:回溯、剪枝-LeetCode47. 全排列 II(可重複數字) https://blog.csdn.net/IOT_victor/article/details/107073704
更簡潔的代碼(推薦!便於拓展,思路與下面的一樣)
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
# nums 選擇列表,depth深度, path 路徑,used 標記數組!,res 結果
def dfs(nums, size, depth, path, used, res):
# 結束條件:nums 中的元素全都在 path 中出現
if depth == size:
res.append(path[:]) # 需要傳遞下path的拷貝,否則對path的修改會影響到結果
return
for i in range(size):
# used[i]==False,表示未被用過
if not used[i]:
# 做選擇
used[i] = True
path.append(nums[i])
# 進入下一層決策樹
dfs(nums, size, depth + 1, path, used, res)
# 撤銷選擇
used[i] = False
path.pop()
size = len(nums)
if len(nums) == 0:
return []
used = [False for _ in range(size)]
res = []
dfs(nums, size, 0, [], used, res)
return res
nums = [1,2,3]
s = Solution()
print(s.permute(nums))
另一種寫法
回溯法模板 https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-xiang-jie-by-labuladong-2/
回溯算法的框架如下,核心就是 for 循環裏面的遞歸,在遞歸調用之前「做選擇」,在遞歸調用之後「撤銷選擇」
result = []
def backtrack(路徑, 選擇列表):
if 滿足結束條件:
result.add(路徑)
return
for 選擇 in 選擇列表:
做選擇
backtrack(路徑, 選擇列表)
撤銷選擇
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
# nums 選擇列表, track 路徑
def trackBack(nums, track):
# 結束條件:nums 中的元素全都在 track 中出現
if len(track) == len(nums):
res.append(track[:]) # 需要傳遞下track的拷貝,否則對track的修改會影響到結果
return
for i in nums:
# 排除不合法的選擇
if i in track:
continue # 結束當前循環進入下一循環
# 做選擇
track.append(i)
# 進入下一層決策樹
trackBack(nums, track)
# 撤銷選擇
track.pop()
res = []
track = [] # 路徑
trackBack(nums, track)
return res
nums = [1,2,3]
s = Solution()
print(s.permute(nums))
時間複雜度:O(n ∗ n!),其中 n 爲序列的長度
空間複雜度:O(n),其中 n 爲序列的長度。除答案數組以外,遞歸函數在遞歸過程中需要爲每一層遞歸函數分配棧空間,所以這裏需要額外的空間且該空間取決於遞歸的深度,這裏可知遞歸調用深度爲 O(n)