回溯题型总结

回溯

因为回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改不了回溯法就是穷举的本质。

代码模板:

backTracking(参数){
	if(终止条件){
	    保存结果;
		终止返回;
	}
	for(横向遍历数组中的元素){
		处理;
		backTracking(参数);
		撤销处理,恢复现场;
	}
}

有以下题型(图片来自“代码随想录”):
在这里插入图片描述

去重:

递归的过程中当遇到当前值与前面的值相同且前面的值也没有加入到集合,跳过这个值。这样做的理由是,当能遍历到目前这个节点,说明前面的元素已经被遍历过了,标记数组used又显示没遍历,说明前面这个元素已经恢复了现场。考虑到当前元素与前面的元素相等,把当前元素加入集合生成的各种排列其实已经前面的元素已经实现过了,再加入集合会造成重复。

去重:1.boolean数组去重 2.同层set集合去重
boolean数组去重:

条件:需要对数组排序,改变了数组的元素顺序。
使用方法:当前元素与前面的元素相同且前面的元素的使用标志为false,则跳过当前元素。
缺点:要排序
优点:效率高,时间复杂度小
同层set集合去重:
条件:无
使用方法:每进入一个递归,新建一个set集合,单层遍历(横向遍历)时,若当前元素已在set中存在,则跳过当前元素。
缺陷:因为只能本层的元素去重,不能对不同父节点的元素一致顺序不一致的情况做排除。
优点:不需要排序

在不排序的情况下,使用set可以排除掉元素一致,顺序一致的情况,但是对元素一致,顺序不一致的情况不能排除,如对数组{2,1,2,2}子集,会出现{1,2},{2,1}。
这也是可以使用同层的set集合可以给“递增子序列”去重,却不能给未排序的“子集问题”“组合问题”去重的原因。(比如对于数组{1,2,1,2}求递增子序列,使用set不会出现{1,2}两次,因为同层像元素会跳过)

排列问题:求一个数组的所有排列组合

横向遍历:从头遍历整个数组,选择一个没有被加入的元素,进入下一轮递归
纵向遍历(回溯):深度就是数组长度

子集问题: 求一个数组的所有子集。

横向遍历:变量start作为起始下标,从start开始往后,每个元素都一个个加入集合,每加入一个,便进入下一轮递归,递归结束后,恢复现场,在集合中删除这个元素。
纵向遍历(回溯):深度等于start到最后一个元素的长度。终止条件是start指向了数组长度(刚越界)。

组合问题:N个数里面按一定规则找出k个数的集合

拓展题型:限定长度;去重;
变量:start标记单层循环的起始,target是目标对象,每次递归target减去选中的那个元素值,当target为0,结束回溯。
横向遍历:从start开始向左遍历,target依次减去每个不大于target的元素,进入下一层递归。递归参数start取i,不要给i加1,start的移动靠单层遍历来实现。
纵向遍历(回溯):当target为0,结束回溯。
针对限定长度问题,在递归开始处判断集合li的长度等于目标长度,同时target减小为0
去重:数组排序,boolean使用标记数组

分割问题:一个字符串按一定规则有几种切割方式

有判断方法,当满足分割条件,便进行切割,加入集合。
横向遍历:start表示起始下标,横向遍历的i充当右边界,右边界的取值范围是从start开始到末尾,截取start到右边界的字符串,判断这些字符串是否满足条件,如果满足条件,下一层的递归start取右边界+1。
纵向遍历(回溯):终止条件是start指向了数组长度(刚越界),深度不固定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值