代码随想录DAY22 - 回溯算法 - 08/21

news2025/1/12 4:07:37

目录

理论回顾

什么是回溯法

回溯法的效率

回溯法解决的问题

如何理解回溯

组合

题干

思路和代码

递归法

递归优化:剪枝

组合总和Ⅲ

题干

思路和代码

递归法

递归优化

电话号码的字母组合

题干

思路和代码

递归法


理论回顾

什么是回溯法

回溯是一种类似枚举的搜索方法,回溯和递归相辅相成。

回溯法的效率

回溯法本质是穷举,也就是检索所有可能最后才找出结果,因此效率并不高。一般为了提高效率都会进行剪枝操作。

回溯法解决的问题

回溯法,一般可以解决如下几种问题:

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

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

  • 子集问题:一个N个数的集合里有多少符合条件的子集

  • 排列问题:N个数按一定规则全排列,有几种排列方式

  • 棋盘问题:N皇后,解数独等等

如何理解回溯

回溯解决的问题可以抽象为树形结构,因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度就构成了树的深度。递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。

组合

题干

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

链接:. - 力扣(LeetCode)

思路和代码

递归法

将问题拆解为先选定组合中的一个数,先记录包含这个数且满足条件的组合,再递归从剩余的 n-1 个数中找组合。

  • 递归参数和返回值:递归参数是集合大小 n,组合大小 k,组合起始位置 startIndex;在递归过程中不断更新组合和结果集。

  • 递归结束的条件:当组合数组已经达到题目要求的组合大小,说明一个组合已经被找到,将该组合插入结果集后返回。

  • 递归顺序:先确定组合的起始元素 startIndex,再递归从剩余的 n - startIndex 个元素里继续填充组合。

class Solution {
public:
    vector<int> composition; // 记录组合
    vector<vector<int>> result; // 记录所有组合结果
    void backTracking(int n, int k, int startIndex){
        if (composition.size() == k){
            // 当组合大小已满足 k,说明已经找到一个组合,插入结果集
            result.push_back(composition);
            // 返回到上一层
            return;
        }
        for (int i = startIndex; i <= n; ++i) {
            composition.push_back(i); // 填充组合的一个位置,接下来要填充下一个位置
            backTracking(n,k,i+1); // 找起点为 j+1 的组合数
            composition.pop_back(); // 回溯的时候要记得弹出之前插入的数
        }
    }
    vector<vector<int>> combine(int n, int k) {
        backTracking(n,k,1); // 起始从 1 开始
        return result;
    }
};
递归优化:剪枝

当集合中剩余的元素已经没法凑够组合大小时,就不必再进入循环找组合中了。也就是说,只有当 组合中已有的元素个数 + 集合中剩余的元素个数 ≥ 组合大小 时,即当 composition.size() + (n-i+1) >= k 时才需要进入循环。

class Solution {
public:
    vector<int> composition; // 记录组合
    vector<vector<int>> result; // 记录所有组合结果
    void backTracking(int n, int k, int startIndex){
        if (composition.size() == k){
            // 当组合大小已满足 k,说明已经找到一个组合,插入结果集
            result.push_back(composition);
            // 返回到上一层
            return;
        }
        for (int i = startIndex; composition.size()+(n-i+1) >= k; ++i) { // for 循环条件中进行剪枝
                                // 修改了进入循环的条件!!
            composition.push_back(i); // 填充组合的一个位置,接下来要填充下一个位置
            backTracking(n,k,i+1); // 找起点为 j+1 的组合数
            composition.pop_back(); // 回溯的时候要记得弹出之前插入的数
        }
    }
    vector<vector<int>> combine(int n, int k) {
        backTracking(n,k,1); // 起始从 1 开始
        return result;
    }
};

组合总和Ⅲ

题干

题目:找出所有相加之和为 nk 个数的组合,且满足下列条件:

  • 只使用数字 1 到 9

  • 每个数字 最多使用一次

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

链接:. - 力扣(LeetCode)

思路和代码

从 1~9 九个数字中选 k 个数组合,若组合之和满足 n ,则插入结果集。

递归法

在上一题的基础上,找出每一个组合,如果组合之和为 n,才插入结果集,否则直接返回。

class Solution {
public:
    int sum = 0; // 记录组合数之和
    vector<int> composition; // 记录组合
    vector<vector<int>> result; // 记录所有组合的结果
    void backTracking(int k, int n, int startIndex){
        if (composition.size() == k){
            if (sum == n){ // 当组合之和 sum 等于目标和 n 时,才插入结果集!
                result.push_back(composition);
            }
            return;
        }
        for (int i = startIndex; i <= 9; ++i) {
            composition.push_back(i);
            sum += i;
            backTracking(k,n,i+1);
            composition.pop_back();
            sum -= i;
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        backTracking(k,n,1);
        return result;
    }
};
递归优化

原来的集合中包含 1~9 九个数字,且是升序的,而我们是从前往后、从小到大寻找组合,当组合之和 sum 已经大于目标和 n 时,说明后续的组合只会更大,不需要再进入循环中了。

class Solution {
public:
    int sum = 0; // 记录组合数之和
    vector<int> composition;
    vector<vector<int>> result;
    void backTracking(int k, int n, int startIndex){
        if (composition.size() == k){
            if (sum == n){
                result.push_back(composition);
            }
            return;
        }
        for (int i = startIndex; composition.size()+(9-i+1) >= k && sum+i <= n; ++i) { // 剪枝
            					// 同理,第一个剪枝操作是当剩余的元素已经凑不够组合大小时,停止循环
            					// 第二个剪枝操作是若 组合之和 已经大于 n 了,就没必要进入循环了
            composition.push_back(i);
            sum += i;
            backTracking(k,n,i+1);
            composition.pop_back();
            sum -= i;
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        backTracking(k,n,1);
        return result;
    }
};

电话号码的字母组合

题干

题目:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

说明:

  • 0 <= digits.length <= 4

  • digits[i] 是范围 ['2', '9'] 的一个数字。也就是说不会输入除了 2 ~ 9 以外的字符

链接:. - 力扣(LeetCode)

思路和代码

首先要知道对应的数字都能映射哪些字母,那么就建立一个 map,键值对为 {数字,字符串(能映射的所有字母)}。这道题本质上也是找组合,只不过找的是不同字符的组合,且在找组合之前得先映射。

递归法

递归法的思路是将问题分解为:每次先确认传入的字符串中第一个数字对应的字符,再递归去确认字符串之后的数字对应的字符。

class Solution {
public:
    unordered_map<int,string> numsToChar{
        {2,"abc"},{3,"def"},{4,"ghi"},{5,"jkl"},
        {6,"mno"},{7,"pqrs"},{8,"tuv"},{9,"wxyz"}
    };
    string composition; // 存储组合
    vector<string> result; // 记录所有组合的结果
    void backTracking(string digits){
        if (digits.size() == 0){
            // 当传入的字符串为空,说明已经找到一个组合,插入结果集
            result.push_back(composition);
            return;
        }
        
        int num = digits[0]-'0'; // 每次都要确认第一个数字
        string s = numsToChar[num]; // 将数字映射为字符串
        for (char c : s) {
            composition.push_back(c); // 已经插入一个字符
            string newDigits;
            // 调整 digits,而不是改 startIndex
            if (digits.size() > 1) newDigits = digits.substr(1); // 要从剩余的字符串中寻找元素插入组合
            else newDigits = "";
            backTracking(newDigits); // 继续递归寻找元素
            composition.pop_back();
        }
    }
    vector<string> letterCombinations(string digits) {
        if (digits.empty()) return {};
        backTracking(digits);
        return result;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python模块依赖注入实现依赖反转使用详解

概要 在软件开发中,依赖注入(Dependency Injection, DI)是一种实现依赖反转(Inversion of Control, IoC)的设计模式,它可以提高代码的灵活性和可测试性。通过依赖注入,模块之间的耦合度被降低,使得代码更容易扩展和维护。在Python开发中,依赖注入虽然不像某些静态类型…

mac安装xmind

文章目录 介绍软件功能下载安装1.下载完成后打开downloads 双击进行安装2.将软件拖到应用程序中3.在启动台中搜索打开4.提示损坏问题解决5.执行完成关闭命令窗口6.打开成功&#xff0c;点击继续&#xff0c;跳过登录7.打开成功后&#xff0c;点击关于 小结 介绍 XMind 是一款流…

专家翻译和本地化对中国商品推广的影响

随着中国企业不断扩大其在全球市场的影响力&#xff0c;有效推广其产品的需求从未如此重要。中国产品在海外成功推广的一个重要因素是专家翻译和本地化。这些服务不仅仅是将文本从一种语言转换为另一种语言&#xff1b;它们涉及调整产品和营销策略&#xff0c;以适应目标市场的…

提升职业竞争力,亚马逊云科技认证助你云端腾飞

在如今云计算快速发展的时代&#xff0c;获得行业领先的认证已成为提升职业竞争力的关键。作为全球最受欢迎的云服务提供商之一&#xff0c;亚马逊云科技提供了广泛的认证路径&#xff0c;帮助专业人士验证其在不同领域的技能和知识。无论你是刚刚踏入云计算领域的新手&#xf…

免费分享:2018中国光伏发电潜力长期年平均值数据(附下载方法)

Solargis&#xff0c;是GeoModel Solar公司的旗舰产品&#xff0c;由斯洛伐克技术精英Marcel Suri等人创立&#xff0c;是全球光伏领域重要的软件服务提供者。它集成了太阳辐射、光伏数据、气象及地理信息的综合数据库&#xff0c;并通过先进算法&#xff0c;为用户提供太阳能资…

联想2510彩色复印机报错CD40故障检修

你是否曾经遇到过联想2510彩色复印机报错CD40的问题,却无从下手?你是否曾经为联想2510彩色复印机CD40的故障而苦恼?别担心,吴师傅来给您提供专业的解决方案。 这篇文章主要介绍“联想2510彩色复印机CD40故障如何维修”,在日常操作中,相信很多小伙伴在联想2510彩色复印机报…

python学习(1)-- window10安装pycharm

pycharm官网&#xff1a;Download PyCharm: The Python IDE for data science and web development by JetBrains 一、安装pycharm 1.进入官网&#xff0c;选择社区版&#xff0c;点击下载。 2.下载完成后&#xff0c;打开下载的exe文件。 3.打开后出现如下界面&#xff0c;点…

宠物空气净化器怎么选?新手必看猫用除毛空气净化器热门品牌推荐

作为资深铲屎官来说&#xff0c;一到换毛季节&#xff0c;家里的猪咪经常会出现掉毛的情况&#xff0c;而且如果不勤打扫的话&#xff0c;粑粑的臭味也挺重的。如果长期不清理家里的浮毛&#xff0c;很容易就会得鼻炎。 看了身边好几个铲屎官都在用宠物空气净化器&#xff0c;…

四、4 逻辑操作符

按位与、按位或关注二进制位 逻辑与、逻辑或只关注真假 1、&&逻辑与&#xff08;并且&#xff09; 左边和右边都为真&#xff0c;结果为真&#xff08;为1&#xff09; 有一个为假&#xff0c;结果为假&#xff08;为0&#xff09; 2、|| 逻辑或&#xff08;或者&a…

超市客流量摄像机助力门店获取精准客户群体

在数字化转型的大潮下&#xff0c;零售业正经历着前所未有的变革。为了更好地理解顾客行为并优化店铺运营&#xff0c;新加坡的零售门店开始采用搭载AI智能识别算法的客流计数器系统。这套系统不仅能够精准统计顾客流量&#xff0c;还能提供深入的分析报告&#xff0c;帮助商家…

datax关于postsql数据增量迁移的问题

看官方文档是不支持的 数据源及同步方案_大数据开发治理平台 DataWorks(DataWorks)-阿里云帮助中心 (aliyun.com) 看了下源码有个postsqlwriter 看了下也就拼接sql 将 PostgresqlWriter中的不允许更新先注释了 让他过去先 然后看到 WriterUtil中的对应方法 getWriteTemplat…

2080. 邻接点

代码 #include<bits/stdc.h> using namespace std; int main() {int n,e,i,j,x,y;cin>>n >> e;vector<vector<int>> adj(n1);for(i0;i<e;i){cin>>x>>y;adj[x].push_back(y);}for(i1;i<n;i)sort(adj[i].begin(),adj[i].end())…

蓝星睡莲基因组

蓝星睡莲基因组&#xff0c;ANA物种的模式物种之二~ 来源于The water lily genome and the early evolution of flowering plants&#xff08;nature&#xff0c;2019&#xff09; 参考链接如下 http://waterlily.eplant.org #官网 https://ngdc.cncb.ac.cn/gwh/A…

用Python和大模型如何实现爬虫(爬虫篇)

前言 在数字化时代&#xff0c;数据挖掘与分析能力成为了一项重要技能。Google Colab&#xff0c;作为一个免费的云端Jupyter Notebook平台&#xff0c;为学习者和开发者提供了一个强大的工具&#xff0c;无需配置本地环境即可进行Python编程、数据分析乃至机器学习项目。 本…

redis实战spring-boot-starter-data-redis

SpringBoot集成Redis环境搭建及配置详解_springboot redis 配置-CSDN博客 如何使用Spring Boot框架整合Redis&#xff1a;超详细案例教程_spring-boot-starter-data-redis-CSDN博客 https://blog.csdn.net/weixin_44411039/article/details/133578724 连接池选择及Jedis连接池参…

全球化2.0战略 | ZStack Cloud 支持9种语言

云轴科技ZStack近日宣布&#xff0c;其最新版本的ZStack Cloud已正式发布&#xff0c;可支持9种语言功能&#xff0c;包括中文&#xff08;简体/繁体&#xff09;、英文、俄语、法语、德语、日语、韩语、印尼语和泰语。这一重大更新是ZStack全球化战略2.0的重要一步&#xff0c…

SDK 和 API

什么是 SDK&#xff1f; 软件开发工具包&#xff08;SDK&#xff09;是一组适合于开发人员的平台特定构建工具集。您需要调试器、编译器和库等组件来创建在特定平台、操作系统或编程语言上运行的代码。SDK 将开发和运行软件所需的一切都集中在一处。此外&#xff0c;它们还包含…

c++题目_斐波那契数列

题目描述 大家都知道&#xff0c;斐波那契数列是满足如下性质的一个数列&#xff1a; F11,F21,FnFn−1Fn−2(n∈N∗)F​1​​1,F​2​​1,F​n​​F​n−1​​F​n−2​​(n∈N​∗​​) 请你求出 Fn%(1097)F​n​​%(10​9​​7) 的值。 输入 一行一个正整数 nn &#xff08…

《黑神话:悟空》全网互动量超1.8亿,百万天命人重走西游

四年磨一剑&#xff0c;一剑破长空。 8月20日10点&#xff0c;《黑神话&#xff1a;悟空》正式开服&#xff0c;同时轰动了国内外游戏圈子&#xff0c;冲顶国内各大社媒平台&#xff0c;一天包揽120个热搜。上线之后&#xff0c;《黑神话&#xff1a;悟空》火速登顶Steam热销游…

基于vue框架的保定市清苑区妇幼保健院收费管理系统6vqb8(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;医生,药品信息,销售信息,销售退货,供应商,药品采购,过期退货 开题报告内容 基于Vue框架的保定市清苑区妇幼保健院收费管理系统开题报告 一、引言 随着医疗改革的深入和信息技术的飞速发展&#xff0c;医疗机构的运营效率与服务质量成…