回溯算法模板要义及题型总结

回溯模板

一、算法流程

回溯就是穷举法
穷举的话有两个方向一个是深度就是利用递归函数,另一个是横向遍历利用for循环
在这里插入图片描述
运行流程:
终止条件控制我们什么时候返回,然后跳回本层,相对的就是执行完了本层的backtraceing()
2、弹出一个数值我们插入的,
3、继续for循环,等到本层都遍历完了,就会由于for循环结束。跳到上一层
在这里插入图片描述

2、模板

void backtracking(参数)
 {
    if (终止条件) //等我们取到足够就数字,就使用return返回本层
    {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

for循环出局条件的i已经超出了查找范围,也就是我们横向遍历结束了
return 是结束我们的深度遍历,跳回本层开始横向遍历

组合

因为{1,2,3}中选择两个数字有几种组合
随机选取的话就是六种,但是明显重复了组合是无序的
{1,2}、{1,3}、{2、3}、{2,1}、{3,1}、{3、2}
好马不吃回头草,我们设置一个变量startindex来控制选择的时候的搜索范围
backtracking(i++) 代表了每进行一次递归,都要选择不同的数字,就像是一根树枝,一样延伸
for(i = startindex;;i++) 我们将i = startindex ,i++ 这样每次横向搜索都是向前的

本质上最核心的就是好马不吃回头草的,我们使用上面两个i++,实现

排列

对应排列来说
{1,2}、{1,3}、{2、3}、{2,1}、{3,1}、{3、2},这六个都是不一样的,好马可以吃回头草
这样我们就不需要startindex,当时也不能乱选,出现{1,1}、{2、2}我们要保证一个元素只能选择次
这样的话我们就引入了数组used,要是谁使用了这样元素就在used中标记一下,回溯的时候就标记还原

去重

我们树枝是可以选择重复数字的,但是同一个树层是不可以选择同一数字,尽管它们不是同一个
1、sort排序
2、在插入之前判断这个前面的是不是相同
3、判断是不是树层重复

题型总结

一、组合

对于组合来说{1,2} 和{2,1}都是一样的结果,所以为了避免出现一样的结过,我们使用startindex控制每次取数字的可以选用范围

 void backtracking(int n, int k, int startIndex) {
        if (path.size() == k) {
            result.push_back(path);
            return;
        }
        for (int i = startIndex; i <= n; i++) {
            path.push_back(i); // 处理节点 
            backtracking(n, k, i + 1); // 递归
            path.pop_back(); // 回溯,撤销处理的节点
        }
    }

名词解释 n:可以选择的个数 k:我们需要的个数 path 存放我们选择中的组合 result :存放我们已经选择好的组合
startindex:控制我们每次选择数字的搜索范围,避免发生重复的事情 回溯:退出一个元素,然后我们就可以继续选择

注意:startindex在每次递归一层就会加一,每次横向for循环一次也会加一

流程解释 1、等我们path存放了足够的数字,就执行终止条件,跳回本层,相对的就是执行完了本层的backtraceing()
2、path.pop_back() 弹出一个数值,i++
3、继续for循环,等到本层都遍历完了,就会由于for循环结束。跳到上一层(横向遍历)
在这里插入图片描述

题型分析

1、可选取的数字可以重复,可选数字无重复

只要使用上面的模板,就可以

不可以重复取一个数字:进行递归的时候startindex需要加一,不可以取之前的数字
可选取的数字无重复:结果不需要去重

2、可选择的数字可以重复
深度递归的时候,startindex不需要加一

3、可选数字有重复(横向选择重复的数字会造成结果重复)
这样我们最后的结果就会出现重复,我们要去重
1、我们传入数组的时候,使用sort排序
2、for循环中,在将数字插入path之前判断这个数字与之前插入的是否相同,并且判断是树枝重复还是树层重复
只有树层重复才要舍去

4、数字与号码
1、先将号码转换成字符,将10个数字对应的字符存放到一个容器中
2、这样我们每次选择的数组都是不同的,我们要做好调整

2、分割

在这里插入图片描述
终止条件是
我们切割线已经到了最后一个数字后面
startindex是从0开始,当startindex >=s.size(),已经切空了
在这里插入图片描述

什么是回文串
使用双指针,一个指针从前往后,一个指针从后往前,如果前后指针所指向的元素是相等的,就是回文子串

题型分析

1、普通回文子串

在插入path之前切下的是不是回文串,要是不是就继续横向遍历下一个

2、复用IP地址
与普通回文子串差不多在插入path之前也要查看是否合法、不行就下一行,当时这个比较特殊一旦前面出现不合法的后面都不合法了,直接break
终止条件
我们需要切四段,没切成就会在后面加一都好,等逗号数目为三,就表示切完了,要是最后一段也合法,就放进result

3、子集

1、普通子集
子集不是收集最后结果,而是过程产生的结果也要,result就不是存放在终止条件的下面,而是上面这样过程都能收集
2、集合有重复元素’
比上面一个多了一个去重,在插入之前判断是否横向重复是的话就跳过

4、排列

1、普通全排列
不要startindex,每次搜索都是重头开始,使用一个used数组来存放标记,来记录哪些元素是否被使用
2、数组中有重复
与上面一个多了一个出重的步骤,在插入之前,要是是重的就continue

5、棋盘问题

6、其他

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值