題目
輸入一個字符串,打印出該字符串中字符的所有排列。
你可以以任意順序返回這個字符串數組,但裏面不能有重複元素。
示例:
輸入:s = “abc”
輸出:[“abc”,“acb”,“bac”,“bca”,“cab”,“cba”]
輸入:s = “aab”
輸出:[“aab”, “aba”, “baa”]
限制:1 <= s 的長度 <= 8
思路
兩種思路:
- 遞歸:第一個位置確定後,後面的n-1個位置的確定就是小規模問題了
- 回溯:使用全局變量記錄返回結果,內部定義函數來執行回溯操作
# 遞歸
def perm(s):
if len(s) == 1: # 邊界
return [s]
res = []
used = set()
for i in range(len(s)): # 第一個可選的
if s[i] in used: # 剪枝
continue
used.add(s[i])
sub_res = perm(s[:i]+s[i+1:])
res.extend([s[i]+p for p in sub_res])
return all
# 回溯
def perm2(s):
n = len(s)
res = []
def dfs(t, path): # 深度優先
if len(path) == n: # 節點
res.append(path)
used = set()
for i in range(t): # 可選擇的
if s[i] in used: # 剪枝
continue
used.add(t[i])
path += t[i] # 入棧
dfs(t[:i]+t[i+1:], path)
path -= t[i] # 出棧
dfs(s, "")
return res
代碼實現中注意的點:
- 使用
used
進行剪枝 - 對於列表或者字符串
s,len(s)=n
,s[k],k>=n
非法,但是s[k:]
是合法的(等於[]
或者""
) - 遞歸直接返回求解結果,回溯使用全局變量記錄結果,內部定義函數實現(回溯)操作
- 遞歸的套路:用小規模的結果構成大規模的結果
- 回溯的套路:實際上就是樹的前序遍歷
def dfs(path, t): # path:記錄路徑列表,t:選擇列表
if path 包含葉子:
一定的操作
return
for i in t: # 遍歷選擇列表
path.append(i) # 進行選擇
dfs(path, t_next) # 對子節點進行遍歷
path.pop() # 撤銷選擇