题目
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
输入: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 res
# 回溯
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() # 撤销选择