面试经典 150 题-回溯
LeetCode 面试经典 150 题-回溯
从今天开始练习ACM模式的题目,从牛客上找力扣对应或相似的题目。
字符串组合
穷举
- 使用treeset去重,重定义比较函数。
- 外层循环枚举字符串长度,内层循环枚举起始位置,加入集合。
1 |
|
- 时间复杂度:生成所有字符串$O(n^2)$,排序$O(n^2 \log (n^2))$,因为最多生成$n^2$个字符串。
- 空间复杂度:$O(n^2)$
电话号码的字母组合
回溯法
这道题的核心是 回溯法(Backtracking),类似于一个多叉树的遍历问题。
步骤:
构建映射关系:用哈希表存储 数字 -> 字母 的映射,例如 '2' -> "abc",'3' -> "def"。
回溯递归:
遍历输入 digits,对每个数字对应的字母 逐个尝试。
递归深入下一层,直到构造完所有的字母组合。
递归结束后回溯(撤销当前选择),尝试下一个可能的组合。
边界情况:输入为空时,返回空列表。
1 |
|
- 时间复杂度:$O(3^m * 4^n)$
- 空间复杂度:O(m+n),空间复杂度主要取决于哈希表以及回溯过程中的递归调用层数,哈希表的大小与输入无关,可以看成常数,递归调用层数最大为m+n。
组合
回溯法
首先,从 1 到 n 中选择一个数字,并递归地继续选择下一个数字,直到组合的大小达到 k。当组合完成时,将其添加到结果中。在递归过程中,通过回溯移除最后添加的元素,回到上一步继续尝试其他可能的组合。这样能够生成所有从 1 到 n 中选择 k 个数的组合。
1 |
|
- 时间复杂度:$O(C(n,k) \times k)$,组合的总数为 C(n,k) = n!/(k!(n-k)!),对于每个组合,我们需要O(k)的时间来创建新的列表并添加到结果中。
- 空间复杂度:O(k),递归的最大深度为k,因为我们需要选择k个数。
全排列
回溯法
首先,将输入数组 nums 转换为列表 cur。然后,通过递归函数 backtrack 实现回溯算法生成所有排列。在每一层递归中,遍历从当前索引 index 到列表末尾的所有元素,并通过交换来生成新的排列。每当递归到达 cur.size() 时,表示一个完整的排列已生成,添加到结果 res 中。回溯过程中使用 Collections.swap 恢复元素顺序,以便探索其他排列。
1 |
|
- 时间复杂度:O(n * n!),backtrack的调用次数是O(n!),需要将当前答案使用O(n)的时间复制到答案数组中。
- 空间复杂度:O(n),递归栈空间,不计返回值空间。
N皇后II
回溯法
定义每列、左上-右下、右上-左下标记数组,尝试对于每一行放置皇后,遍历每一列,计算对角线下标,然后递归下一行,再回溯。
1 |
|
- 时间复杂度:O(n!)
- 空间复杂度:O(n)
括号生成
回溯法
- 回溯函数参数:结果集和当前括号组合,左括号剩余数和右括号剩余数。
- 递归结束条件:左括号剩余数和右括号剩余数都是0.
- 如果当前左括号剩余数大于0,那么可以选择左括号,左括号剩余数-1再递归遍历,回溯;如果当前左括号剩余数小于右括号剩余数,那么可以选择右括号,右括号剩余数-1再递归遍历,回溯。
- 返回结果集。
1 |
|
- 时间复杂度:$\frac{4^n}{\sqrt{n}}$
- 空间复杂度:O(n),结果不计入空间。
单词搜索
回溯
- 对每一个位置作为单词起始进行搜索,如果搜索到了就可以返回true;
- 回溯函数参数:网格,单词,当前搜索位置行列坐标,单词索引;
- 递归结束条件:单词索引遍历到最后;
- 剪枝:超出边界、当前位置已访问过、当前位置字符不等于当前单词字符;
- 对上下左右四个方向进行搜索,回溯;
- 返回结果。
1 |
|
- 时间复杂度:$O(mn \cdot 3^L)$,除了第一次可以进入4个分支以外,其余时间我们最多会进入3个分支。
- 空间复杂度:O(m * n + L)。
面试经典 150 题-回溯
http://example.com/2025/02/15/posts/hot150-11/