代码随想录算法训练营第十九天|认识回溯,77.组合

认识回溯

77.组合 

认识回溯

回溯法也可以叫做回溯搜索法,它是一种搜索的方式。

回溯是递归的副产品,只要有递归就会有回溯。

回溯法的效率

回溯的本质是穷举,即使加了剪枝操作,其本质也还是穷举

回溯法解决的问题

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

理解回溯法

回溯法解决的问题都可以抽象为树形结构

回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度,都构成的树的深度

递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。

回溯法模板

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

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

 光看理论确实有点懵,还需要再实践中加深理解耶!

77.组合

回溯三步骤:

  • 递归函数的返回值以及参数
vector<vector<int>> result; // 存放符合条件结果的集合
vector<int> path; // 用来存放符合条件结果
  • 回溯函数终止条件
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); // 递归:控制树的纵向遍历,注意下一层搜索要从i+1开始
    path.pop_back(); // 回溯,撤销处理的节点
}

成员变量

  • result:用于存储所有符合条件的组合集合。
  • path:用于暂存当前正在探索的组合路径。

backtracking函数:是回溯算法的核心,接受三个参数:

  • n:表示选择范围的上限。
  • k:目标组合的长度。
  • startIndex:当前递归探索的起始索引,避免重复选择。

递归逻辑

  • 终止条件:当path的长度等于k时,表示找到了一个有效的组合,将其添加到result中并返回。
  • 递归遍历:从startIndex开始,遍历到n。对于每一个数i,将其添加到path中(处理节点),然后递归调用backtracking函数,探索下一个数字,起始索引为i + 1(保证不会选择到重复的数字)。递归返回后,执行回溯操作,即从path中移除最后添加的数字,以探索其他可能的组合路径。

combine函数

  • 是公共接口,用于初始化状态并调用backtracking函数开始递归探索。
  • 在开始前清空resultpath,确保结果集是从空开始的。虽然在题目给定的单次调用场景中,清空操作可能不是必须的,但在多次调用同一个对象的方法时,清空操作可以保证每次调用结果的独立性。
  • 调用backtracking开始递归探索,并最终返回所有找到的组合。
class Solution {
private:
    vector<vector<int>> result; // 存放符合条件结果的集合
    vector<int> path; // 用来存放符合条件结果
    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(); // 回溯,撤销处理的节点
        }
    }
public:
    vector<vector<int>> combine(int n, int k) {
        result.clear(); 
        path.clear();  
        backtracking(n, k, 1);
        return result;
    }
};

优化 

  • 剪枝逻辑:通过计算[startIndex, n]区间内剩余的选择数量是否足够满足组合长度k的需求来决定是否继续递归。这里的剪枝条件为i <= n - (k - path.size()) + 1。这个条件确保了只有当剩余的选择足够填满剩余所需的组合长度时,才继续递归。
  • 效率提升:这种剪枝可以显著减少递归的次数,特别是当n较大且k也较大时,可以避免大量无效的递归调用,从而提升算法的执行效率。
#include <vector>
using std::vector;

class TreeNode {
    // 树节点定义省略,与题目描述一致
};

class Solution {
private:
    vector<vector<int>> result; // 存放所有符合条件的组合
    vector<int> path; // 当前的组合路径
    void backtracking(int n, int k, int startIndex) {
        // 如果当前路径的长度已经满足k,将其加入到结果集中
        if (path.size() == k) {
            result.push_back(path);
            return;
        }

        // 优化的核心逻辑:剪枝
        // 还需要的元素数量为 k - path.size()
        // 因此,[startIndex, n] 中至少应有 k - path.size() 个元素
        // 即 startIndex 最大为 n - (k - path.size()) + 1
        for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) {
            path.push_back(i); // 处理当前节点
            backtracking(n, k, i + 1); // 递归探索下一层
            path.pop_back(); // 回溯,撤销当前节点的处理结果
        }
    }
public:
    vector<vector<int>> combine(int n, int k) {
        result.clear();
        path.clear();
        backtracking(n, k, 1);
        return result;
    }
};

python

初始化一个空的result列表来存储所有符合条件的组合,以及一个空的path列表来存储当前的组合路径。

定义了一个backtracking函数,它接受一个参数startIndex,表示当前递归的起始位置。

backtracking函数内部,首先进行剪枝操作。如果当前路径长度加上区间[startIndex, n]内所有可能的选择的数量小于k,说明即使将剩余所有选项都加入到path中,也无法满足组合长度为k的要求,因此直接返回。

如果当前路径长度已经达到k,则将path的一个副本加入到result中。

然后通过一个for循环遍历从startIndexn的所有数字,尝试将每个数字加入到path中,并递归调用backtracking函数以探索后续的数字。每次递归调用后,通过path.pop()回溯,以撤销上一步的选择。

最后,通过调用backtracking(1)开始递归过程,并返回最终的结果result

class Solution:
    def combine(self, n: int, k: int) -> [[int]]:
        result = []  # 存放所有符合条件的组合
        path = []  # 当前路径,即一个可能的组合
        
        def backtracking(startIndex: int):
            # 剪枝:path 长度加上区间 [startIndex, n] 的长度小于 k,不可能构建出长度为 k 的 path
            if len(path) + (n - startIndex + 1) < k:
                return
            
            # 如果当前路径的长度已经满足 k,将其加入到结果集中
            if len(path) == k:
                result.append(path[:])
                return
            
            for i in range(startIndex, n + 1):
                path.append(i)  # 处理节点
                backtracking(i + 1)  # 递归探索下一层
                path.pop()  # 回溯,撤销当前节点的处理结果

        backtracking(1)
        return result

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/400002.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【2024软件测试面试必会技能】Jmeter_性能测试(4):性能测试脚本的优化

性能测试脚本的优化 以PHP论坛为例&#xff1a;http://47.107.178.45/phpwind/ 根据上一篇的性能测试(3&#xff09;的脚本进行优化&#xff1b;见下图&#xff1a; 如上图中&#xff0c;把发帖和回帖的事务添加到随机控制器中&#xff0c;登录操作添加到仅一次控制器中&…

Python学习笔记——自定义函数(传递任意数量的实参)

Python允许函数从调用语句中收集任意数量的实参。例如下面自定义函数制作一个披萨&#xff0c;它需要接受很多配料&#xff0c;但无法预先确定顾客要点多少种配料。 下面行数只有一个形参*toppings&#xff0c;不管调用语句提供多少个实参&#xff0c;这个参数都会收集到&…

阿里云/腾讯云幻兽帕鲁服务器为什么更新/重启之后,服务器存档没了?

有的朋友说&#xff0c;他的阿里云幻兽帕鲁服务器重启了一下后&#xff0c;服务器存档就没了&#xff1f;这是怎么回事呢&#xff0c;其实可能的原因&#xff0c;一是服务器还有重启完成&#xff0c;也就是游戏服务端还没有启动&#xff0c;就登进去&#xff0c;可能会显示网络…

智慧公厕是什么?智慧公厕对智慧城市的意义

城市的信息化发展需要催化了智慧城市&#xff0c;公共厕所作为城市的重要民生设施&#xff0c;如何实现更高阶的信息化建设&#xff0c;成为一个重要课题。那么&#xff0c;智慧公厕是什么&#xff1f;为什么它对智慧城市的建设如此重要&#xff1f;本文以智慧公厕源头厂家广州…

git工具

一、命令行工具 二、Git 客户端可视化工具-推荐 1.常用工具 tortoisegit 官网 https://tortoisegit.org/ 推荐 sourcetree 官网https://www.sourcetreeapp.com/ 2.tortoisegit安装 2.1 下载安装包 2.2 下载语言包 2.3 安装 2.4 安装语言包 5.使用 5.1 新建分支 5.2 切换分支…

力扣精选算法100道——Z字形变换(模拟专题)

目录 &#x1f388;了解题意 &#x1f388;算法原理 &#x1f6a9;先处理第一行和最后一行 &#x1f6a9;再处理中间行 &#x1f388;实现代码 &#x1f388;了解题意 大家看到这个题目的时候肯定是很迷茫的&#xff0c;包括我自己也是搞不清楚题目什么意思&#xff0c;我…

R cox回归 ggDCA报错

临床预测模型的决策曲线分析&#xff08;DCA&#xff09;&#xff1a;基于ggDCA包 决策曲线分析法&#xff08;decision curve analysis&#xff0c;DCA&#xff09;是一种评估临床预测模型、诊断试验和分子标记物的简单方法。 我们在传统的诊断试验指标如&#xff1a;敏感性&a…

游戏同步+游戏中的网络模块

原文链接&#xff1a;游戏开发入门&#xff08;九&#xff09;游戏同步技术_游戏数据同步机制流程怎么开发-CSDN博客 游戏开发入门&#xff08;十&#xff09;游戏中的网络模块_游戏开发组网-CSDN博客 3.同步技术的基本常识&#xff1a; a.同步给谁&#xff1f;某个用户&…

Day04 嵌入式---基本定时器

定时器概述 1、软件定时原理 使⽤纯软件的⽅式实现定时功能。 存在的问题&#xff1a;定时不太精准。CPU死等。 1&#xff09;压栈出栈需要花费时间 2&#xff09;ARM流⽔线体系架构的原因 2、定时器定时原理 使用精准的时基&#xff0c;通过硬件方式&#xff0c;实现定…

力扣日记2.21-【回溯算法篇】46. 全排列

力扣日记&#xff1a;【回溯算法篇】46. 全排列 日期&#xff1a;2023.2.21 参考&#xff1a;代码随想录、力扣 46. 全排列 题目描述 难度&#xff1a;中等 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&…

Spring6学习技术|IoC|手写IoC

学习材料 尚硅谷Spring零基础入门到进阶&#xff0c;一套搞定spring6全套视频教程&#xff08;源码级讲解&#xff09; 有关反射的知识回顾 IoC是基于反射机制实现的。 Java反射机制是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&…

P2957 [USACO09OCT] Barn Echoes G

P2957 [USACO09OCT] Barn Echoes G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P2957 题目分析 对于求单个字符串的哈希值相当于求前缀和&#xff0c;而求单个字符串的子串的哈希值则相当于求其区间和&#xff1b; 那么只需求两个…

面试经典150题——旋转图像

"You are never too old to set another goal or to dream a new dream." - C.S. Lewis​ 1. 题目描述 2. 题目分析与解析 2.1 思路一 还是最简单的尝试模拟人的思维&#xff0c;如果对于一个普通人解决该题目&#xff0c;那就是先把第一行放在最后一列 或者 把第…

入职字节外包才一个月,我就离职了

有一种打工人的羡慕&#xff0c;叫做“大厂”。 真是年少不知大厂香&#xff0c;错把青春插稻秧。 但是&#xff0c;在深圳有一群比大厂员工更庞大的群体&#xff0c;他们顶着大厂的“名”&#xff0c;做着大厂的工作&#xff0c;还可以享受大厂的伙食&#xff0c;却没有大厂…

惠尔顿 网络安全审计系统 任意文件读取漏洞复现

0x01 产品简介 惠尔顿网络安全审计产品致力于满足军工四证、军工保密室建设、国家涉密网络建设的审计要求&#xff0c;规范网络行为&#xff0c;满足国家的规范&#xff1b;支持1-3线路的internet接入、1-3对网桥&#xff1b;含强大的上网行为管理、审计、监控模块&#xff1b…

猫毛过敏不能养猫了吗?除猫毛好的宠物空气净化器品牌有哪些?

让我们来探讨一下如何让容易过敏的家庭成员和猫咪更好地相处。很多人喜欢猫咪&#xff0c;但与它们相处一段时间后&#xff0c;可能会出现鼻塞、喷嚏和眼泪不断的过敏症状。那么&#xff0c;为什么会过敏呢&#xff1f;这是因为猫的唾液中含有Fel d1蛋白质&#xff0c;当它们舔…

回显服务器的制作方法

文章目录 客户端和服务器TCP和UDP的特点UDP socket api的使用DatagramSocketDatagramPacketInetSocketAddress API 做一个简单的回显服务器UDP版本的回显服务器TCP版本的回显服务器 客户端和服务器 在网络中&#xff0c;主动发起通信的一方是客户端&#xff0c;被动接受的这一方…

SpringBoot+Vue+MySQL:图书管理系统的技术革新

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

怀孕了要把猫送走吗?推荐一款吸猫毛神器—宠物空气净化器

相信大部分家庭都会遇到这样一个二选一的难题&#xff1a;怀孕了还能养猫吗&#xff1f;还是要把猫送走&#xff1f; 许多人担心在孕期与宠物接触可能会导致健康问题&#xff0c;主要是因为弓形虫的存在。然而&#xff0c;实际上感染弓形虫并不容易。如果你真的很担心&#xf…

绘图神器VisIt初步使用

文章目录 安装绘图图像属性 VisIt是一款用于可视化科学数据的开源软件&#xff0c;适用于大型数据集&#xff0c;并提供了丰富的可视化和分析功能。 安装 首先下载VisIt&#xff0c;然后下载一些示例以及测试数据&#xff0c;地址在github上。 下载之后安装&#xff0c;有两…