力扣算法刷题Day33|休息日总结:回溯 & 去重

回溯 〉理论基础

  • 回溯是递归的副产品,只要有递归就会有回溯,所以回溯法也经常和二叉树遍历,深度优先搜索混在一起,因为这两种方式都是用了递归。
  • 优点:用递归控制for循环嵌套的数量
  • 缺点:回溯法就是枚举/暴力搜索,并不是什么高效的算法,最多再剪枝一下

回溯 〉适用题型

  • 组合问题:N个数里面按一定规则找出k个数的集合
  • 排列问题:N个数按一定规则全排列,有几种排列方式
  • 切割问题:一个字符串按一定规则有几种切割方式
  • 子集问题:一个N个数的集合里有多少符合条件的子集
  • 棋盘问题:N皇后,解数独等等

回溯 〉解题技巧

  • 树形结构:回溯法的题目都可以将遍历过程抽象为树形结构方便理解。for循环横向遍历,递归纵向遍历,回溯不断调整结果集
  • 回溯三部曲:1)返回值,参数;2)终止条件;3)单层逻辑
  • 剪枝优化:在for循环上做剪枝操作是回溯法剪枝的常见套路。for循环在寻找起点的时候要有一个范围,如果这个起点到集合终止之间的元素已经不够题目要求的k个元素了,就没有必要搜索了。
  • 去重方式:使用set去重的版本相对于used数组的版本效率都要低很多。使用used数组在时间复杂度上几乎没有额外负担,使用set去重,不仅时间复杂度高了,空间复杂度也高了

回溯 〉解题技巧 〉组合问题

  • startIndex避免重复选取当前元素:用于控制for循环的起始位置。对于组合问题,如果是一个集合来求组合的话,就需要startIndex;如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex。
  • 在多个集合中枚举元素:字典存不同集合映射关系,切换集合后从头开始遍历,无需startIndex控制起点去重
  • 回溯过程中给答案集去重:利用used数组去重,在有序集合中,当前元素和前一元素值相同时,即candidates[i] == candidates[i - 1]的情况下
    • “树枝去重”:used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
    • “树层去重”:used[i - 1] == false,说明同一树层candidates[i - 1]使用过

回溯 〉解题技巧 〉切割问题

  • 切割问题可以抽象为回溯问题:组合问题是枚举单个数值选择符合条件的s[i],切割问题是枚举切割线的位置,即枚举字符子串选取符合条件的s[startIndex, i](区间左闭右闭)
  • 模拟切割线:startindex是上一层已经确定了的分割线,i是这一层试图寻找的新分割线
  • 递归终止条件:当startindex = len(string),分割线已切到末尾
  • 在递归循环中截取子串:string[startindex:i+1]
  • 判断回文:双指针一首一尾判断元素是否一致

回溯 〉解题技巧 〉子集问题

  • 答案收集:收集所有节点,而非组合问题中仅收集叶子节点
  • 无终止条件:for循环遍历完自动跳出返回
  • 非有序数组中去重:利用set()记录每层使用过的值,针对同一父节点的同层去重,无需判断i-1即可去重。

回溯 〉解题技巧 〉排列问题

回溯 〉解题技巧 〉图论问题

  • 讲顺序:1)每层都是从0开始搜索而不是startIndex;2)需要used数组记录path里都放了哪些元素
  • 树层去重和树枝去重都能得到唯一答案,但树层去重效率优于树枝去重
  • 用dict/list两套解法,难点在容器的选择和使用

回溯 〉解题技巧 〉棋盘问题

  • 二维矩阵:棋盘的宽度就是for循环的长度,递归的深度就是棋盘的高度
  • 二维递归:一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,一行一列确定下来之后,再来一个for循环递归遍历这个位置放9个数字的可能性

回溯 〉复杂度分析

  • 时间复杂度都是指数级别

回溯 〉复杂度分析 〉子集问题

  • 时间复杂度:O(2^n),因为每一个元素的状态无外乎取与不取,所以时间复杂度为O(2^n)
  • 空间复杂度:O(n),递归深度为n,所以系统栈所用空间为O(n),每一层递归所用的空间都是常数级别,注意代码里的result和path都是全局变量,就算是放在参数里,传的也是引用,并不会新申请内存空间,最终空间复杂度为O(n)

回溯 〉复杂度分析 〉组合问题

  • 时间复杂度:O(2^n),组合问题其实就是一种子集的问题,所以组合问题最坏的情况,也不会超过子集问题的时间复杂度。
  • 空间复杂度:O(n),和子集问题同理。

回溯 〉复杂度分析 〉排列问题

  • 时间复杂度:O(n!),这个可以从排列的树形图中很明显发现,每一层节点为n,第二层每一个分支都延伸了n-1个分支,再往下又是n-2个分支,所以一直到叶子节点一共就是 n * n-1 * n-2 * ..... 1 = 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值