牛客网 面试笔试 TOP101 | LeetCode 46. 全排列
1. 题目
描述
给出一组没有重复
的数字,返回该组数字的所有排列
。
例如:
[1,2,3]的所有排列如下 [1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2], [3,2,1]. (以数字在数组中的位置靠前为优先级,按字典序排列输出。)
数据范围:数字个数 0 <n≤6
要求:空间复杂度 O(n!),时间复杂度 O(n!)
示例1
输入:
[1,2,3]
返回值:
[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例2
输入:
[1]
返回值:
[[1]]
2. 解题思路
从本题开始,讲解回溯算法,下面需要重点来看一下什么是回溯算法:
回溯算法是一种通过试错法(试探+回退)解决约束满足问题的通用策略,常用于解决组合优化、排列、子集生成等问题。其核心思想是逐步构建解,若发现当前路径无法达成目标,则回退到上一步尝试其他可能性。
核心思想
- 试探:按条件扩展当前解的候选可能性。
- 验证:若当前路径不满足约束,立即放弃(剪枝)。
- 回退:撤销上一步选择,回到之前的状态继续尝试其他路径。
适用场景
- 组合问题:如子集、排列、全排列(如
n 选 k
)。- 约束满足问题:如数独、八皇后、数独。
- 穷举搜索:当问题规模较小时,回溯可遍历所有可能解。
操作
也就是说解决一个回溯问题,实际上就是一个决策树的遍历过程。在这个过程中只需要思考三个问题: (1)路径:也就是已经做出的选择; (2)选择列表:也就是你当前可以做的选择; (3)结束条件:也就是到达决策树底层,无法再做选择的条件。
回溯算法模板:
result = [] #结果集 path=[] #路径 def backtracking(选择列表): # 2.递归终止条件 if 满足结束条件: # 2.1 存放结果 result.add(满足条件的路径) # 2.2 返回 return # 1.选择:在本层集合中遍历元素 for 选择 in 选择列表: # 1.1 处理节点:做出选择 做选择 # 1.2 递归(缩小数据范围。数据范围缩小到一定程度,会触发递归终止条件) backtracking(选择列表) # 1.3 回溯,撤销选择 撤销选择
注:核心就是 for 循环里面的递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」。
回溯结构如下图所示:
对回溯算法有了了解之后,就可以套用回溯算法模板完成数字的全排列了,具体思路如下:
如果文字描述的不太清楚,你可以参考视频的详细讲解。
- Python版本:www.bilibili.com/cheese/play…
- Java版本:www.bilibili.com/cheese/play…
- Golang版本:www.bilibili.com/cheese/play…
3. 编码实现
核心代码如下:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param num int整型一维数组
* @return int整型二维数组
*/
func permute(num []int) [][]int {
// write code here
result = make([][]int, 0)
backtracking(num, 0)
return result
}
var result [][]int
func backtracking(num []int, index int) {
// 2.递归终止条件:分枝进入结尾,找到一种排列
if index == len(num)-1 {
//2.1 存放结果
tmp := append([]int{}, num...) //将num结果复制一份(新建一个切片,如果是引用原来切片,是地址引用,num内容改变时,result数据也会发生改变)
result = append(result, tmp)
//2.2 返回
return
}
//1.选择:在本层集合中遍历元素
for i := index; i < len(num); i++ {
//1.1 处理节点:元素互换【如:1,2,3(1放到最前面:1与1交换);2,1,3(2放到最前面:2与1交换);3,2,1(3放到最前面:3与1交换)】
swap(num, i, index)
// 1.2 递归:缩小数列区间【对第i+1个再进行相似的操作(递归),如1,2,3(1固定,再对剩余的2,3进行类似的操作)】
backtracking(num, index+1)
//1.3 回溯,撤销选择:将互换的元素还原【将交换的数据变换回来,再进行下一轮操作】
swap(num, i, index)
}
}
func swap(num []int, i int, index int) {
num[i], num[index] = num[index], num[i]
}
具体完整代码你可以参考下面视频的详细讲解。
- Python版本:www.bilibili.com/cheese/play…
- Java版本:www.bilibili.com/cheese/play…
- Golang版本:www.bilibili.com/cheese/play…
4.小结
数字项的全排列是回溯算法的典型应用,这时可以直接套用回溯算法模板完成。具体操作流程为:
- 选择:在本层集合中遍历元素。
- 处理节点:做出选择;
- 递归(缩小数据范围。数据范围缩小到一定程度,会触发递归终止条件);
- 回溯,撤销选择。
- 递归终止。
- 存放结果;
- 返回。
《数据结构与算法》深度精讲课程正式上线啦!7 大核心算法模块全解析:
✅ 链表
✅ 二叉树
✅ 二分查找、排序
✅ 堆、栈、队列
✅ 回溯算法
✅ 哈希算法
✅ 动态规划
无论你是备战笔试面试、提升代码效率,还是突破技术瓶颈,这套课程都将为你构建扎实的算法思维底座。🔥立即加入学习打卡,与千名开发者共同进阶!
- Python编码实现:www.bilibili.com/cheese/play…
- Java编码实现:www.bilibili.com/cheese/play…
- Golang编码实现:www.bilibili.com/cheese/play…
对于数据结构与算法,我们总结了一套【可视化+图解】方法,依据此方法来解决相关问题,算法变得易于理解,写出来的代码可读性高也不容易出错。具体也可以参考视频详细讲解。
今日佳句:独学而无友,则孤陋而寡闻。