代码随想录算法训练营三期 day 25 - 回溯 (2) (补)

news2024/9/21 17:27:09

216. 组合总和III

题目描述: 216. 组合总和 III
原文链接: 216. 组合总和 III
视频链接: 216. 组合总和 III

树形结构

请添加图片描述

回溯三部曲:

确定回溯函数参数及返回值
和 77. 组合 一样,依然需要一维数组 path 来存放符合条件的结果,二维数组 res 来存放结果集。
这里依然定义 path 和 res 为全局变量。

vector<int> path;        // 符合条件的结果
vector<vector<int>> res; // 存放结果集

接下来还需要如下参数:
targetSum(int)目标和,也就是题目中的 n。
sum(int)为已经收集的元素的总和,也就是 path 里元素的总和。
k(int)就是题目中要求 k 个数的集合。
startIndex(int)为下一层 for 循环搜索的起始位置。

    vector<int> path;
    vector<vector<int>> res;
    void backtracking(int targetSum, int sum, int k, int startIndex) {

确定终止条件
所以如果 path.size() 和 k 相等了,就终止。
如果此时 path 里收集到的元素和(sum) 和 targetSum(就是题目描述的 n)相同了,就用 res 收集当前的结果。

        if (path.size() == k) {
            if (sum == targetSum) {
                res.push_back(path);
            }
            return;
        }

确定单层递归逻辑
本题和 77. 组合 区别之一就是集合固定的就是 9 个数 [1,…,9],所以 for 循环固定 i <= 9(如图)
请添加图片描述
处理过程就是 path 收集每次选取的元素,相当于树形结构里的边,sum 来统计 path 里元素的总和。
处理过程 和 回溯过程 是一一对应的,处理有加,回溯就要有减!

        for (int i = startIndex; i <= 9; i++) {
            sum += i;
            path.push_back(i);
            backtracking(targetSum, sum, k, i + 1);
            path.pop_back();
            sum -= i;
        }

代码如下:

class Solution {
private:
    vector<int> path;
    vector<vector<int>> res;
    void backtracking(int targetSum, int sum, int k, int startIndex) {
        if (path.size() == k) {
            if (sum == targetSum) {
                res.push_back(path);
            }
            return;
        }
        for (int i = startIndex; i <= 9; i++) {
            sum += i;
            path.push_back(i);
            backtracking(targetSum, sum, k, i + 1);
            path.pop_back();
            sum -= i;
        }
    }
public:
    vector<vector<int>> combinationSum3(int k, int n) {
        backtracking(n, 0, k, 1);
        return res;
    }
};
剪枝

已选元素总和 sum 如果已经大于 targetSum 了,那么往后遍历就没有意义了,直接剪掉。
那么剪枝的地方可以放在递归函数开始的地方,剪枝代码如下:

if (sum > targetSum) { // 剪枝操作
    return;
}

for 循环的范围也可以剪枝,i <= 9 - (k - path.size()) + 1;
剪枝后代码如下:

class Solution {
private:
    vector<int> path;
    vector<vector<int>> res;
    void backtracking(int targetSum, int sum, int k, int startIndex) {
        if (sum > targetSum) {
            return;
        }
        if (path.size() == k) {
            if (sum == targetSum) {
                res.push_back(path);
            }
            return;
        }
        for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) {
            sum += i;
            path.push_back(i);
            backtracking(targetSum, sum, k, i + 1);
            path.pop_back();
            sum -= i;
        }
    }
public:
    vector<vector<int>> combinationSum3(int k, int n) {
        backtracking(n, 0, k, 1);
        return res;
    }
};

17. 电话号码的字母组合

题目链接:17. 电话号码的字母组合
原文链接:17. 电话号码的字母组合
视频链接:17. 电话号码的字母组合

数字和字母如何映射

可以使用 map 或者定义一个二维数组,例如:string lettersMap[10],来做映射:

    const string lettersMap[11] = {
        "", 
        "", 
        "abc", 
        "def", 
        "ghi", 
        "jkl", 
        "mno", 
        "pqrs", 
        "tuv",  
        "wxyz"
    };
树形结构

请添加图片描述
图中可以看出遍历的深度,就是输入 “23” 的长度,而叶子节点就是我们要收集的结果,输出 [“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”]。

回溯三部曲

确定回溯函数参数及返回值
首先需要一个字符串 s 来收集叶子节点的结果,然后用一个字符串数组 res 保存起来,这两个变量依然定义为全局。
再来看参数,参数指定是有题目中给的 string digits,然后还要有一个参数就是 int 型的 index。
这个 index 是记录遍历第几个数字了,就是用来遍历 digits 的(题目中给出数字字符串),同时 index 也表示树的深度。

string s;
vector<string> res;
void backtracking(const string& digits, int index)

确定终止条件
例如输入用例 “23”,两个数字,那么根节点往下递归两层就可以了,叶子节点就是要收集的结果集。
那么终止条件就是如果 index 等于 输入的数字个数(digits.size)了(本来 index 就是用来遍历 digits 的)。
然后收集结果,结束本层递归。

if (index == digits.size()) {
    res.push_back(s);
    return;
}

确定单层递归逻辑
首先要取 index 指向的数字,并找到对应的字符集(手机键盘的字符集)。
然后 for 循环来处理这个字符集,代码如下:

int digit = digits[index] - '0';        // 将index指向的数字转为int
string letters = lettersMap[digit];      // 取数字对应的字符集
for (int i = 0; i < letters.size(); i++) {
    s.push_back(letters[i]);            // 处理
    backtracking(digits, index + 1);    // 递归,注意index + 1,一下层要处理下一个数字了
    s.pop_back();                       // 回溯
}

注意这里 for 循环,要从 0 开始遍历。
因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而 77. 组合 和 216.组合总和III 都是求同一个集合中的组合。
代码如下:

class Solution {
private:
    const string lettersMap[11] = {
        "", 
        "", 
        "abc", 
        "def", 
        "ghi", 
        "jkl", 
        "mno", 
        "pqrs", 
        "tuv",  
        "wxyz"
    };
    string s;
    vector<string> res;
    void backtracking(const string& digits, int index) {
        if (index == digits.size()) {
            res.push_back(s);
            return;
        }
        int digit = digits[index] - '0';
        string letters = lettersMap[digit];
        for (int i = 0; i < letters.size(); i++) {
            s.push_back(letters[i]);
            backtracking(digits, index + 1);
            s.pop_back();
        }
    }
public:
    vector<string> letterCombinations(string digits) {
        if (digits.size() == 0) {
            return res;
        }
        backtracking(digits, 0);
        return res;
    }
};

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

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

相关文章

leetcode-每日一题-计算应缴税款总额(简单,数学逻辑)

给你一个下标从 0 开始的二维整数数组 brackets &#xff0c;其中 brackets[i] [upperi, percenti] &#xff0c;表示第 i 个税级的上限是 upperi &#xff0c;征收的税率为 percenti 。税级按上限 从低到高排序&#xff08;在满足 0 < i < brackets.length 的前提下&am…

(19)go-micro微服务filebeat收集日志

文章目录一 Filebeat介绍二 FileBeat基本组成三 FileBeat工作原理四 Filebeat如何记录文件状态:五 Filebeat如何保证事件至少被输出一次六 安装Filebeat七 使用Filebeatfilebeat.yml编写八 最后一 Filebeat介绍 filebeat是Beats中的一员。 Beats在是一个轻量级日志采集器&…

2022——>2023

2022年对于我来说&#xff0c;是极其不平凡的一年&#xff0c;因为在这一年&#xff0c;我面临了人生的第一次重大的选择——高考。老师们常说&#xff1a;“一分压倒一操场人。”这句话是我高考看完自己的成绩之后深有体会的。超过湖南本科线没几分的我&#xff0c;志愿真的是…

剖析“类和对象” (中) -------- CPP

在上一篇博客中 (剖析“类和对象” (上) -------- CPP) 提到&#xff0c;一个类中什么成员都没有的称为“空类”。一个“空类”中真的什么都没有吗&#xff1f; 其实不然&#xff0c;任何类中什么都不写时&#xff0c;编译器会自动生成一下六个默认成员函数。 默认成员函数&am…

Fisco Bcos区块链二(搭建使用控制台,体验Holleworld合约调用)

文章目录区块链开荒技术文档&#xff1a;https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/index.html2. 配置及使用控制台准备依赖启动并使用控制台3. 部署及调用HelloWorld合约编写HelloWorld合约&#xff08;此处不需要编写&#xff0c;控制台已内置&#xff…

【每日一道智力题】之海盗分金币(上)

文章目录题目&#xff1a;解答&#xff1a;题目变形&#xff1a;解答&#xff1a;总结题目&#xff1a; 5个海盗抢到了100枚金币&#xff0c;每一颗都一样的大小和价值。 他们决定这么分&#xff1a; 抽签决定自己的号码&#xff08;1&#xff0c;2&#xff0c;3&#xff0c;4…

IDEA 2022 创建 Spring Boot 项目详解

如何用 IDEA 2022 创建并初始化一个 Spring Boot 项目&#xff1f; 目录 如何用IDEA 2022创建并初始化一个Spring Boot项目&#xff1f; 0. 环境说明 1. 创建Spring Boot项目 2. 编写初始化代码 0. 环境说明 IDEA 2022.3.1JDK 1.8Spring Boot 1. 创建 Spring Boot 项目…

Linux常用命令——smbclient命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) smbclient 交互方式访问samba服务器 补充说明 smbclient命令属于samba套件&#xff0c;它提供一种命令行使用交互式方式访问samba服务器的共享资源。 语法 smbclient(选项)(参数)选项 -B<ip地址>&…

【SpringCloud20】SpringCloud Alibaba Seata处理分布式事务

目录1.分布式事务问题2.Seata简介2.1 是什么2.2 作用2.3 下载2.4 如何使用3.Seata-Server安装3.1 下载网址3.2 下载版本3.3 seata解压到指定目录并修改文件3.3.1 nacos新增配置文件3.3.2 修改application.yml3.4 数据库新建seata3.5 在seata里建表3.6 启动Nacos端口号88483.7 启…

Spring介绍

Spring是分层的全栈式的轻量级开发框架,以IOC和AOP为核心,官网是https://spring.io Spring优势 1 方便解耦,简化开发 Spring通过容器,将对象的创建从代码中剥离出来,交给Spring控制,避免直接编码造成模块之间的耦合度高,用户也不必自己编码处理对象的单例和多例控制,主要关注接…

C语言基础知识(36)

C语言中的数组和指针有什么区别数组和指针之间的一个重要区别是数组中元素的地址始终是固定的&#xff0c;不能在执行时修改地址&#xff0c;但对于指针&#xff0c;可以根据需要更改指针的地址。分支结构1.简单if语句C语言中的分支结构语句中的if条件语句。简单if语句的基本结…

Linux内核驱动初探(一) LVDS显卡

目录 0. 前言 1. menuconfig 2. 编译报错与打补丁 3. 设备树与display-timings 4. 拓展&#xff1a;RGB24 0. 前言 这次的工作主要是把某项目设备上(iMX6DL)的内核版本从 4.19.x 升级到 5.15.32&#xff0c;是作为该项目整个BSP升级计划的一部分。 该内核升级工作移交给…

PX4+Offboard模式+代码控制无人机起飞(Gazebo)

参考PX4自动驾驶用户指南 https://docs.px4.io/main/zh/ros/mavros_offboard_cpp.html 新建ros项目工程 mkdir -p px4_offboard_ws/src接着进入文件编译一下 cd px4_offboard_ws catkin_make进入src目录&#xff0c;创建ros功能包 catkin_create_pkg t1_offboard_rtakeoff …

Springboot+vue基于java的家教管理平台

系统分为用户和管理员&#xff0c;教师三个角色 用户的主要功能有&#xff1a; 1.用户注册和登陆系统 2.查看系统的公告信息 3.用户查看家教教师简历信息 4.用户查看课程信息 5.用户查看招聘教师信息&#xff0c;在线应聘教师 6.用户个人中心修改个人资料&#xff0c;修改密码…

Python数据清洗2

一、函数数据处理 1.在dataframe中使用apply方法&#xff0c;调用自定义函数对数据进行处理 2.可以使用astype函数对数据进行转换 3.可以使用map函数进行数据转换 二、数据分组运算 1.使用groupby方法进行分组计算&#xff0c;得到分组对象GroupBy 2.语法为df.groupby(…

在甲骨文云容器实例(Container Instances)上部署chrome

甲骨文云推出了容器实例&#xff0c;这是一项无服务器计算服务&#xff0c;可以即时运行容器&#xff0c;而无需管理任何服务器。 今天我们尝试一下通过容器实例部署chrome。 Step1. 创建容器实例 在甲骨文容器实例页面&#xff0c;单击"创建容器实例"&#xff0c;…

LInux(四)进程控制(创建、终止、等待、替换)

目录 一、进程创建 1、pid_t fork(void) 2、写时拷贝技术&#xff08;父子进程间代码共享、数据独有&#xff09; 3、vfork()--创建一个子进程 4、fork创建子进程流程是什么样的&#xff1f; 5、一个关于fork的程序 6、程序a 7、 程序b 二、进程终止 1、在main函数中…

E2PROM 蓝桥杯 stm32 AT24C02读写函数

本文 代码使用 HAL 库 。 文章目录前言一、AT24C02 读写函数&#xff1a;1. 读函数2. 写函数&#xff1a;二. AT24C02 读写地址&#xff0c;原理图三. 延时问题总结下一节讲解 MCP4017。使用 E2PROM 来计算板子的上电次数 实验效果。前言 本文 先列出 AT24C02 读写函数 &#…

【蓝桥杯】简单数论3——素数

1、素数判断 素数定义:只能被1和自己整除的正整数。注:1不是素数&#xff0c;最小素数是2。 判断一个数n是不是素数:当n≤时&#xff0c;用试除法;n>时&#xff0c;试除法不够用&#xff0c;需要用高级算法&#xff0c;例如Miller_Rabin算法。 试除法&#xff1a;用[2, n…

MySQL —— 库操作

目录 一、库操作 1. 创建数据库 2. 创建数据库案例 二、字符集和校验规则 1. 查看系统默认字符集以及校验规则 2. 查看数据库支持的字符集 3. 查看数据库支持的字符集校验规则 4. 校验规则对数据库的影响 三、操纵数据库 1. 查看数据库 2. 显示创建语句 3. 修改数…