Day 25 组合(优化)216.组合总和III 17.电话号码的字母组合

组合(优化)

先给出组合问题的回溯部分代码:

   	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(); // 回溯,撤销处理的节点
        }
    }

剪枝操作优化

​ 首先明白为什么可以剪枝,以此处的n个元素操作k个元素为例,当处理的后序元素数量小于k时可以直接剪枝掉,以节省内存空间;

​ 例如,n = 4,k = 4的话,那么第一层for循环的时候,从元素2开始的遍历都没有意义了;在第二层for循环,从元素3开始的遍历都没有意义了;依次类推:(图里的每一个节点,都代表着一个for循环

​ 由图可知,由于回溯算法的实现可以视为for循环里嵌套着递归;(此处补充一下回溯到底是怎么实现的,如图)

​ 实际上剪枝操作就是在缩小for循环的范围,即改变for循环的循环条件,缩小范围:

​ 因为如果for循环选择的起始位置之后的元素个数已经不足我们需要的元素个数了,那么就没有必要搜索了

​ 具体剪枝逻辑如下:

​ 已经选择了path.size()个元素;

​ 则后续剩余所需的元素个数为k - path.size();

​ 那么要求剩余元素个数(n-i) >= (k - path.size());

​ 则要求i <= n - (k - path.size()) + 1;

​ 为啥要**+1**?,因为这个地方是i可以取到的上界,而取的集合要求是闭区间,比如n=4,k=3的时候,当path.size() = 0时,那么[1,2,3]和[2,3,4]数组都是合法的目标数组;

​ 剪枝后即为

	//略
	for(int i = startIndex; i <= n - (k - path.size()) + 1; i++)
    //略

组合总和Ⅲ

找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

说明:

  • 所有数字都是正整数。
  • 解集不能包含重复的组合。

示例 1: 输入: k = 3, n = 7 输出: [[1,2,4]]

示例 2: 输入: k = 3, n = 9 输出: [[1,2,6], [1,3,5], [2,3,4]]

​ 思路和77.组合的思路是一致的,但是多了一个相加等于n的限制条件;

​ 很容易知道,k就是树的深度,9就是树的宽度,树形结构如图所示:

​ 可以看出,这里很明显是需要进行剪枝操作的,多余的节点太多了;

    vector<vector<int>>	res;
	vector<int>	path;
	void backtracking(int targetSum, int k, int sum, 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++ ){//剪枝,注意此处不是减k而是k-path.size()
            sum += i;
            path.push_back(i);
            backtracking(targetSum, k, sum, i+1);
            sum -= i;
            path.pop_back();
        }
    }

​ 整体代码如下:

class Solution {
private:
    vector<vector<int>>	res;
	vector<int>	path;
	void backtracking(int targetSum, int k, int sum, 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, k, sum, i+1);
            sum -= i;
            path.pop_back();
        }
    }
public:
    vector<vector<int>> combinationSum3(int k, int n) {
        path.clear();
        res.clear();
        backtracking(n, k, 0, 1);
        return res;
    }
};

电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

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

17.电话号码的字母组合

示例:

  • 输入:“23”
  • 输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].

说明:尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

​ 题目输入的是字符串,但是字符串中的字符同时是对应着另一组字符串的数字,所以这里要进行一个映射的操作;

​ 可以用const string的形式进行映射,也可以使用map进行映射存储:

	//写法1
	const string letterMap[10] = {
    "", // 0
    "", // 1
    "abc", // 2
    "def", // 3
    "ghi", // 4
    "jkl", // 5
    "mno", // 6
    "pqrs", // 7
    "tuv", // 8
    "wxyz", // 9
	};
	//写法2
	std::map<int, std::string> letterMap;
    letterMap[0] = "";
    letterMap[1] = "";
    letterMap[2] = "abc";
    letterMap[3] = "def";
    letterMap[4] = "ghi";
    letterMap[5] = "jkl";
    letterMap[6] = "mno";
    letterMap[7] = "pqrs";
    letterMap[8] = "tuv";
    letterMap[9] = "wxyz";


​ 同理,将回溯过程以树形结构表达出来:

​ 即树的深度由输入的字符串决定;

	const string letterMap[10] = {
    "", // 0
    "", // 1
    "abc", // 2
    "def", // 3
    "ghi", // 4
    "jkl", // 5
    "mno", // 6
    "pqrs", // 7
    "tuv", // 8
    "wxyz", // 9
	};
	vector<string> res;
	string s;
	void backtracking(const string& digits, int index){
        if(index == digits.size()){//终止条件就是如果index 等于输入的数字个数(digits.size)
            res.push_back(s);
            return;
        }
        //单层遍历逻辑
        int digit = digits[index] - '0';//char类型运算得到int型
        string letters = letterMap[digit];//取对应集合的字符串
        for(int i = 0; i < letters.size(); i++){
            s.push_back(letters[i]);
            backtracking(digits, index + 1);
            s.pop_back();
        }      
    }

​ 整体代码如下:

class Solution {
private:
    const string letterMap[10] = {
    "", // 0
    "", // 1
    "abc", // 2
    "def", // 3
    "ghi", // 4
    "jkl", // 5
    "mno", // 6
    "pqrs", // 7
    "tuv", // 8
    "wxyz", // 9
	};
	vector<string> res;
	string s;
	void backtracking(const string& digits, int index){
        if(index == digits.size()){//终止条件就是如果index等于输入的数字个数(digits.size)
            res.push_back(s);
            return;
        }
        //单层遍历逻辑
        int digit = digits[index] - '0';//char类型运算得到int型
        string letters = letterMap[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) {
        s.clear();
        res.clear();
        if (digits.size() == 0) {
            return res;
        }
        backtracking(digits, 0);
        return res;
    }
};

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

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

相关文章

洛谷P1305 新二叉树

Java 代码 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();char arr[][] new char[n][3];for (int i 0; i < n; i) {String strsc.next();char arr1[]str.toCharArray()…

【计算机考研】跨考计算机,需要准备多久才来得及?

9个月跨考计算机&#xff0c;如果选择是408的话&#xff0c;时间稍微有点紧张&#xff0c;前期感觉不大&#xff0c;后期数学408堆在一起会感觉很难受... 很多确定考408的同学都是一开始先从数据结构开始复习的&#xff0c;这样到了中后期觉得自己时间不够了再去转自命题也来得…

UE5数字孪生系列笔记(四)

场景的切换 创建一个按钮的用户界面UMG 创建一个Actor&#xff0c;然后将此按钮UMG添加到组件Actor中 调节几个全屏的背景 运行结果 目标点切换功能制作 设置角色到这个按钮的位置效果 按钮被点击就进行跳转 多个地点的切换与旋转 将之前的目标点切换逻辑替换成旋转的逻…

使用webpack5+TypeScript+npm发布组件库

一、前言 作为一只前端攻城狮&#xff0c;没有一个属于自己的组件库&#xff0c;那岂不是狮子没有了牙齿&#xff0c;士兵没有了武器&#xff0c;姑娘没有了大宝SOD蜜&#xff0c;你没有了我.... 言归正传&#xff0c;下面将给大家介绍如何通过webpack5编译一个TS组件发布到NPM…

Cannot find runner for app ——Android Studio

问题 在修改build.gradle(:app)文件或者其他操作后&#xff0c;出现了无法运行的问题&#xff1a; Cannot find runner for app 如图运行按钮不可点击。 解决方案 点击【File】下的【Sync Project with Gradle Files】同步完成后&#xff0c;一般就可运行了。

树形侧边栏(展开、全选、切换名称)

父文件&#xff1a; index.vue <template><div class"h-full p20px bg-#f5f5f5"><ContentWrap class"w-260px h-[calc(100vh-200px)] min-h-700px"><TenantTree select"tentantSelect" /></ContentWrap></div&…

ExtendSim花生酱加工厂模型

该模型展示了ExtendSim可靠性模块与ExtendeSim离散速率技术相结合的协同作用。 在花生酱加工厂的最初阶段&#xff0c;花生经过烘烤和冷却。冷却后的花生经过热烫或水烫去外皮。这些经过漂白的花生进入过程的混合部分&#xff0c;在研磨机中用盐、葡萄糖和氢化油稳定剂将其粉碎…

链表基础3——单链表的逆置

链表的定义 #include <stdio.h> #include <stdlib.h> typedef struct Node { int data; struct Node* next; } Node; Node* createNode(int data) { Node* newNode (Node*)malloc(sizeof(Node)); if (!newNode) { return NULL; } newNode->data …

【七 (1)指标体系建设-构建高效的故障管理指标体系】

目录 文章导航一、故障概述1、故障&#xff1a;2、故障管理&#xff1a; 二、指标体系概述1、指标2、指标体系 三、指标体系构建难点1、管理视角2、业务视角3、技术视角 四、指标体系构建原则1、与战略目标对齐2、综合和平衡3、数据可获得性4、可操作性5、具体和可衡量6、参与和…

Windows10为Git Bash添加文件传输命令rsync(详细图文配置)

文章目录 1. 安装git bash2. 下载所需要的4个包3. 下载解压包的软件4. 复制每个包下面的usr到git安装目录下4.1 所遇问题4.2 解决 5. 安装完成6. 需要注意 Windows上要使用 rsync命令上传或下载文件&#xff0c;需要使用git bash&#xff0c;git bash没有rsync&#xff0c;需要…

盘点2024年最新可用免费云服务器

随着云计算技术的快速发展&#xff0c;越来越多的企业和个人开始使用云服务器来满足各种业务需求。云服务器作为云计算的核心服务之一&#xff0c;以其弹性扩展、按需付费等特点受到广泛关注。本文将为大家盘点2024年最新可用免费云服务器&#xff0c;助力大家轻松上云&#xf…

Problem #8 [Easy]

This problem was asked by Google. A unival tree (which stands for “universal value”) is a tree where all nodes under it have the same value. Given the root to a binary tree, count the number of unival subtrees. For example, the following tree has 5 un…

【c 语言】声明了一个指针,会给指针分配内存吗?

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;C语言 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步&…

借力社交裂变,Xinstall助你实现用户快速增长

在数字化时代&#xff0c;社交裂变已成为品牌获取新用户、扩大影响力的关键手段。然而&#xff0c;如何有效利用社交裂变&#xff0c;实现用户快速增长&#xff0c;却是许多品牌面临的挑战。今天&#xff0c;我们将为大家介绍一个强大的社交裂变引擎——Xinstall&#xff0c;它…

状态模式【行为模式C++】

1.概述 状态模式是一种行为设计模式&#xff0c; 让你能在一个对象的内部状态变化时改变其行为&#xff0c; 使其看上去就像改变了自身所属的类一样。 2.结构 State(抽象状态类)&#xff1a;定义一个接口用来封装与上下文类的一个特定状态相关的行为&#xff0c;可以有一个或多…

【Linux C | 多线程编程】线程同步 | 互斥量(互斥锁)介绍和使用

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 本文未经允许…

MoneyPrinterTurbo-利用AI大模型,一键生成高清短视频

MoneyPrinterTurbo-利用AI大模型&#xff0c;一键生成高清短视频 在今天的信息爆炸的时代&#xff0c;短视频已经成为最受欢迎的信息传递方式之一。无论是分享生活瞬间&#xff0c;还是传递重要信息&#xff0c;短视频都是最直观&#xff0c;最具影响力的手段。但是&#xff0…

量子城域网系列(四):几种典型的量子密钥分发网络组网方案

通过之前的文章&#xff0c;我们对点对点的量子保密通信网络有了直观的认识&#xff0c;也知道了量子保密通信系统就是利用量子密钥分发产生的无条件安全量子密钥作为系统安全性保证。所以在实际应用中&#xff0c;一个通信网络如果想实现量子加密&#xff0c;就需要建设量子密…

12-项目部署_持续集成

项目部署_持续集成 1 今日内容介绍 1.1 什么是持续集成 持续集成&#xff08; Continuous integration &#xff0c; 简称 CI &#xff09;指的是&#xff0c;频繁地&#xff08;一天多次&#xff09;将代码集成到主干 持续集成的组成要素 一个自动构建过程&#xff0c; 从…

【Linux C | 多线程编程】线程同步 | 总结条件变量几个问题

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 本文未经允许…