代码随想录-回溯法

代码随想录-回溯法

做题模板

做递归题目的时候,可按照下面的模板。

void backtracking(参数) {
	if (终止条件) {
		存放结果;
		return;
	}
	for (选择:本层集合中的元素) {
		处理节点;
		backtracking(路径,选择列表);
		回溯,撤销处理结果;
	}
}

回溯法能够解决如下问题:

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

题目分类总结

组合问题

用递归控制for循环嵌套的数量。
回溯问题的搜索过程:for循环横向遍历,递归纵向遍历,回溯不断调整结果集。

  1. 给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。
    常规操作。可以采取的剪枝优化方法就是i不小于n,而是i < n - (k - path.size())。比如n = 4, k = 4的时候,for循环的时候从元素2开始遍历就没有意义了。
  2. 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
    和上一道题一样,不同的就是有1个相加和的限制。
  3. 电话号码的数字组合:这道题需要提前把数字和字母的映射存在一个数组里面,然后再用回溯的方法去做。
    4.leetcode39 组合总和:这道题目中的数组元素不重复。与上面题目不同的是这个题目可以重复选取数组中的元素,所以在进行递归的时候,startIndex不用加1。
  4. leetcode40 组合总合ii:这道题目中的数组元素是可以重复的,但是数组candidates中的每个元素只能使用一次。具体做法就是:先把数组给排下序,然后让相同的元素可以挨在一起。题目要求不能包含重复的组合。我们要想办法进行去重。我们要进行树层的去重而不是树枝的去重。用used数组来表示这个元素是否被使用过。所以在递归函数中的循环中,要加上如下的代码:
if(i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] = 0) {
	return;
}

用这种方法进行去重。

分割问题

  1. leetcode 131 分割回文串:和组合问题类似。需要在循环中判断一下截取到的这个字符串是不是回文串。判断回文串的方法:1)用两个指针,一个指着头,一个指着尾,然后进行比较,看是否都相等来判断是否是回文字符串。2)把字符串进行反转,然后对原始的字符串和翻转后的字符串进行比较来判断。
  2. leetcode 93 复原IP地址:与上一个分割问题类似,这道题目就需要判断截取的字符串是否是有效的IP地址。

子集问题

  1. leetcode 78 子集:这道题需要把对应的树形结构的元素全部加入最终结果中,所以递归函数中就是不用判断条件的把path加入到result中。
  2. leetcode 90 子集II:题目中的整数数组可能包含重复元素的整数数组,但是解集中不能包含重复的子集。这道题的解法就是leetcode 78加上树层去重。
  3. leetcode 491 递增子序列:这道题目要要求去重,但是不能对题目中的整数数组进行排序,所以不能用之前用的去重方法。所以就需要在对应的树形结构的每一层加一个HashSet类型的变量。这样就可以判断这一层是否已经加入过相同的元素来进行去重。

排列问题

  1. leetcode 46 全排列:和上面问题的解决思路类似,不同的就是需要加入一个used数组,来去看看这个元素有没有被使用过。
  2. leetcode 47 全排列II:在上一个题的基础上,加上树层去重。

重新安排行程

  1. leetcode 332 重新安排行程:这道题有几个点需要注意:
    • 如果处理不好一个往返行程的机票,容易造成死循环的状况。
    • 如果保证在有多种解法的时候,字母排序较小的排在前面呢?
    • 递归的终止条件是什么?
      对应的解决办法为:
    • 用used数组来记录这张机票是否使用过;
    • 在解决这个题之前,根据数组里面每一张机票的到达地对数组进行排序
    Collections.sort(tickets, (a, b) -> a.get(1).compareTo(b.get(1)));
    
    • 递归的终止条件:
    path.size() == ticket.size() + 1;
    
    弄清楚这些问题,这道题就比较容易解决了。因为这道题要求返回一个符合条件的结果就可以了,所以递归函数的返回类型是boolean。

棋盘问题

  1. leetcode 51 N皇后:在这个题目中要明确棋盘的宽度是for循环的长度,递归的深度是棋盘的高度。除此之外,要写一个在棋盘的这个位置放这个皇后是否有效的函数,即检查这一列和两条对角线上是否有皇后。
  2. leetcode 37 解数独:这个题目没有终止条件,在递归函数中遍历行、遍历列、遍历要放的字符来进行处理。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值