剑指offer-38
剑指 Offer 38. 字符串的排列
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
1 | 输入:s = "abc" |
官方题解
对于一个长度为 $n$ 的字符串(假设字符互不重复),其排列方案数共有:
$$
n \times ( n - 1 ) \times ( n - 2 ) \ldots \times 2 \times 1
$$
排列方案的生成:
根据字符串排列的特点,考虑深度优先搜索所有排列方案。即通过字符交换,先固定第 1 位字符( n 种情况)、再固定第 2 位字符( n-1 种情况)、… 、最后固定第 n 位字符( 1 种情况)。
重复排列方案与剪枝:
当字符串存在重复字符时,排列方案中也存在重复的排列方案。
为排除重复方案,需在固定某位字符时,保证 “每种字符只在此位固定一次” ,即遇到重复字符时不交换,直接跳过。
从 DFS 角度看,此操作称为 “剪枝” 。
递归解析
- 终止条件: 当
x = len(c) - 1
时,代表所有位已固定(最后一位只有 1 种情况),则将当前组合c
转化为字符串并加入res
,并返回; - 递推参数: 当前固定位
x
; - 递推工作: 初始化一个 Set ,用于排除重复的字符;将第
x
位字符与$i \in [x, len(c)]$ 字符分别交换,并进入下层递归;- 剪枝: 若
c[i]
在 Set 中,代表其是重复字符,因此 “剪枝” ; - 将
c[i]
加入 Set ,以便之后遇到重复字符时剪枝; - 固定字符: 将字符
c[i]
和c[x]
交换,即固定c[i]
为当前位字符; - 开启下层递归: 调用
dfs(x + 1)
,即开始固定第x + 1
个字符; - 还原交换: 将字符
c[i]
和c[x]
交换(还原之前的交换);
- 剪枝: 若
1 | class Solution: |