代码随想录回溯部分二刷总结
模板
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
for循环横向遍历,递归纵向遍历,回溯不断调整结果集
组合问题
对于单个一维数组通过startIndex来跳转可选择的范围和保证结果为组合而不是排列
startIndex:在树层和树枝都控制了是否能重复选择
剪枝的点:在递归开始时或者for循环体中(树枝剪枝)和在for循环条件中(树层剪枝)
关于组合去重:用used数组来判断树层去重,在candidates[i] == candidates[i - 1]相同的情况下:
used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
used[i - 1] == false,说明同一树层candidates[i - 1]在子序列这种不能对给定数组排序的题目去重,应该在每一层用哈希表去重,这在每一层默认回溯了。
分割问题
可以看做是分割边界位置的组合问题
string类的substr第二个参数是要截取的长度
子集问题
组合和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点
组合和子集同一层取过的元素不会重复取,所以要用startIndex来控制
子集问题一般都不用终值条件
排列问题
用used数组进行树枝元素去重(注意是元素而不是元素的值)
不需要startIndex
棋盘问题
n皇后问题:列对应着层,行对应着深度
解数独:树的每一层是1~9,深度是由行与列嵌套而成
去重的两种写法:used数组和哈希法
相同:都是在树层去重
不同:used:是传参,且需要回溯操作和参照数组有序
哈希法: 在每一层前重新定义一个哈希表,默认回溯
性能分析
子集问题分析:
时间复杂度:O(2n),因为每一个元素的状态无外乎取与不取,所以时间复杂度为O(2n)
空间复杂度:O(n),递归深度为n,所以系统栈所用空间为O(n),每一层递归所用的空间都是常数级别,注意代码里的result和path都是全局变量,就算是放在参数里,传的也是引用,并不会新申请内存空间,最终空间复杂度为O(n)
排列问题分析:
时间复杂度:O(n!),这个可以从排列的树形图中很明显发现,每一层节点为n,第二层每一个分支都延伸了n-1个分支,再往下又是n-2个分支,所以一直到叶子节点一共就是 n * n-1 * n-2 * … 1 = n!。
空间复杂度:O(n),和子集问题同理。
组合问题分析:
时间复杂度:O(2^n),组合问题其实就是一种子集的问题,所以组合问题最坏的情况,也不会超过子集问题的时间复杂度。
空间复杂度:O(n),和子集问题同理。
N皇后问题分析:
时间复杂度:O(n!) ,其实如果看树形图的话,直觉上是O(n^n),但皇后之间不能见面所以在搜索的过程中是有剪枝的,最差也就是O(n!),n!表示n * (n-1) * … * 1。
空间复杂度:O(n),和子集问题同理。
解数独问题分析:
时间复杂度:O(9^m) , m是’.'的数目。
空间复杂度:O( n^2 ),递归的深度是n^2
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!