决战圣地玛丽乔亚重新归来之Day57--算法回溯

上次的题目给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。

使用回溯的方法去解。

 回溯通用模板:

void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}

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

 外层循环n次,也就是n个数,里层执行k次backtracking,代表不断的取第一个数,第二个数,第三个树,一直取到最后一个数满足size=k的情况。

这时达到了终点,return回方法,终于可以执行path.pop_back方法,也就是此时数组的个数回归k-1的情况。

此时回退到最后一次循环的那一层,开始往后循环。

即  若1,2,3,4,5  取3个数组成集合。     第一轮取  1,2,3   放入集合后,   1,2,4    最后一层的循环i+1    然后满足个数后4回退,  1,2,5  结束最后一层的循环

回退到倒数第二层。

1,3,4     1,3,5  startindex的位置为此时i的数字+1,这样不会回头找。

次数最后的所有遍历结果为  1,2,3   1,2,4,  1,2,5    2,3,4  2,3,5   3,4,5

剪枝优化可以让我们的性能更强。这里考虑一个问题,如果我们5个数去取4个数。

当我们的第一层去1, 第二层可取的为2,3

因为如果第一层取1,第二层取4,第三层可取范围为5   总共为三个数,构不成四个数。所以我们在对回溯时候的遍历次数可以加上长度的限制减少多余的循环。

即优化:

for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置

 

组合总和III

找出相加之和为n的k个数的组合。组合数字范围1-9,并且每个数限定使用一次。

这次加了条件,但是回溯的模板不会变。

if(calc(list,k)){

return

}

boolean  void calc(List<Integer> list,int k){判断之和是否为k}

for(int i = xx; i<;i++){

push(i)

backtracking(n,k,1)

removelast()

}

1,2,3  判断是否小于8    小于回溯     1,2,4 小于回溯   1,2,5  等于return

等于或大于,结束整个循环。小于回溯。  如果两个条件结束循环,可以直接考虑对立面的条件填写,会比较容易理解。

最后的代码如下,剪纸是如果和大于目标值返回, 以及不满足个数的情况,9个数9种可能-path.size(已选择个数)

 

posted @   NobodyHero  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示