2023-01-09Day24第七章回溯算法

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

回溯算法三部曲:
1.回溯函数模板返回值以及参数
2.回溯函数终止条件
3.回溯搜索的遍历过程

算法框架

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

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

for 横向遍历(i=1,2,..,),递归纵向遍历
组合问题
77. 组合 - 力扣(Leetcode)

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        res = []
        path = []
        def backtracking(n,k,startindex):
            if len(path) ==k:
                res.append(path[:])
                return
            # 剪枝, 最后k - len(path)个节点直接构造结果,无需递归
            last_index = n-(k-len(path))+1 
            for i in range(startindex,last_index+1):
                path.append(i)
                backtracking(n,k,i+1) #递归
                path.pop() #回溯
        backtracking(n,k,1)
        return res 

对于last_index 处理节点上界的理解:
比如n=15,k=4,len(path)=1时,接下来要选3个数,遍历的起点最大是13,最后一个被选的是[13,14,15],在这个时候14和15开头的长度不够,肯定不符合,就不需要处理可以进行剪枝。
比如n=5,k=3,len(path)=0,需要再选3个数,遍历起点最大的数是3,最后一个被遍历的列表是[3,4,5],对于这个时候4和5开头的就不需要处理了,就是剪枝。
所有可以归纳:
处理节点上界=n-(k-len(path))+1
所以last_index=n-(k-len(path))+1
而last_index+1则是因为range区间左闭右开
这个问题中n相当于树的宽度,k相当于树的深度。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容